You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Haroon Rafique <ha...@utoronto.ca> on 2003/09/25 22:15:53 UTC

Off Topic: mod_perl reverse proxy setup and extracting client's original IP

Hi,

I have a slightly off topic inquiry. I've googled/RTFMed. I run mod_perl
in a reverse proxy setup. Light apache in the front-end, heavy mod_perl
apache in the back-end both running on the same machine.

The front end has the following reverse proxy directives:

ProxyPass        /perl/ http://localhost:8103/perl/
ProxyPassReverse /perl/ http://localhost:8103/perl/

Due to the reverse proxy setup, the original client IP is lost and all IP 
is reported as 127.0.0.1 (front-end). To extract the client's original IP 
I was happy to learn that mod_proxy conveniently adds a X-Forwarded-For 
header to the proxied requests automatically. On the back-end, I use:

PerlPostReadRequestHandler My::ProxyRemoteAddr

where My::ProxyRemoteAddr has code identical to
http://perl.apache.org/docs/1.0/guide/scenario.html#Usage
except for some minor mp2 migrations.

sub My::ProxyRemoteAddr ($) {
    my $r = shift;
   
    # we'll only look at the X-Forwarded-For header if the requests
    # comes from our proxy at localhost
    return Apache::OK
        unless
        ($r->connection->remote_ip =~
         m#^(127\.0\.0\.1|localhost\.localdomain)$#)
         and $r->header_in('X-Forwarded-For');
  
    # Select last value in the chain -- original client's ip
    if( my( $ip ) = $r->headers_in->{'X-Forwarded-For'} =~ /([^,\s]+)$/ ) 
{
        $r->connection->remote_ip($ip);
        $r->log_error("Recorded client IP from X-Forwarded-For header: ",
                $r->headers_in->{'X-Forwarded-For'},
                " as IP: ", $ip);
    }
    
    return Apache::OK;
}

Everything is hunky dory. The back-end access_log have the client's IP 
address and the applications sees the correct address as well.

Here's the twist:

To secure the back-end, direct access to the back-end directly is
prohibited. The back-end config has the following directive to only allow
proxied requests to come through:

<Location />
  order deny,allow
  deny from all
  allow from localhost 127.0.0.1
</Location>

If I keep this directive in the back-end config, the client's original IP 
never makes it to the access_log. The application does however get the 
correct IP address.

apache 2.0.47
mod_perl 1.99_09
perl 5.8.0

Anyone else experienced the same? Needless to say, I would like to keep 
the site secure, as well maintain the client's original IP in the 
logs.

On second thought, this looks more and more like an apache issue.
--
Haroon Rafique
<ha...@utoronto.ca>

Re: Off Topic: mod_perl reverse proxy setup and extracting client's original IP

Posted by Haroon Rafique <ha...@utoronto.ca>.
On Today at 4:15pm, HR=>Haroon Rafique <ha...@utoronto.ca> wrote:

HR> To secure the back-end, direct access to the back-end directly is
HR> prohibited. The back-end config has the following directive to only
HR> allow proxied requests to come through:
HR> 
HR> <Location />
HR>   order deny,allow
HR>   deny from all
HR>   allow from localhost 127.0.0.1
HR> </Location>
HR> 

A kind list member replied to me directly and reminded me that the above
directive is totally unnecessary in my case. A simple 'Listen
127.0.0.1:8103' would achieve the same affect since 127.0.0.1 is only
accessible from the local machine.

I'm reposting to the list in case someone searches the archives.

The originally reported behavior is still an unexplained gotcha. I'm glad
I found an easy workaround that works.

Thanks for listening.
--
Haroon Rafique
<ha...@utoronto.ca>

Re: Off Topic: mod_perl reverse proxy setup and extracting client's original IP

Posted by Torsten Foertsch <to...@gmx.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Thursday 25 September 2003 22:15, Haroon Rafique wrote:
> If I keep this directive in the back-end config, the client's original IP
> never makes it to the access_log. The application does however get the

since you have got the real ip address already on your backend I would simply 
add a note to the request $r->notes(RealIp=>$ip); and log the note instead of 
the ip address or hostname. Your CustomLog probably looks like "%h ..." or 
"%a ...". Change it to "%{RealIp}n ..." and the note will be logged instead.

Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE/c+J5wicyCTir8T4RAgTyAKCk1TLeHw4/x3tMr+TTNtZT5HIWUACeLkPy
cldkDmOeWSQSJSJHhLweCas=
=BG7Y
-----END PGP SIGNATURE-----

Re: Off Topic: mod_perl reverse proxy setup and extracting client's original IP

Posted by Jie Gao <J....@isu.usyd.edu.au>.


On Fri, 26 Sep 2003, Jie Gao wrote:

> Date: Fri, 26 Sep 2003 08:04:14 +1000 (EST)
> From: Jie Gao <J....@isu.usyd.edu.au>
> To: modperl@perl.apache.org
> Subject: Re: Off Topic: mod_perl reverse proxy setup and extracting
>     client's original IP
>
>
>
>
> On Thu, 25 Sep 2003, Haroon Rafique wrote:
>
> > Date: Thu, 25 Sep 2003 16:15:53 -0400 (EDT)
> > From: Haroon Rafique <ha...@utoronto.ca>
> > To: modperl@perl.apache.org
> > Subject: Off Topic: mod_perl reverse proxy setup and extracting client's
> >     original IP
> >
> > Hi,
> >
> > I have a slightly off topic inquiry. I've googled/RTFMed. I run mod_perl
> > in a reverse proxy setup. Light apache in the front-end, heavy mod_perl
> > apache in the back-end both running on the same machine.
> >
> > The front end has the following reverse proxy directives:
> >
> > ProxyPass        /perl/ http://localhost:8103/perl/
> > ProxyPassReverse /perl/ http://localhost:8103/perl/
>
> You might also want to enbale "ProxyPreserveHost" directive, so that
> your backend server can handle virtual servers as well.

Sorry, you can't, I've just found out, for the original request
uses a different port.

Regards,



Jie

Re: Off Topic: mod_perl reverse proxy setup and extracting client's original IP

Posted by Jie Gao <J....@isu.usyd.edu.au>.


On Thu, 25 Sep 2003, Haroon Rafique wrote:

> Date: Thu, 25 Sep 2003 16:15:53 -0400 (EDT)
> From: Haroon Rafique <ha...@utoronto.ca>
> To: modperl@perl.apache.org
> Subject: Off Topic: mod_perl reverse proxy setup and extracting client's
>     original IP
>
> Hi,
>
> I have a slightly off topic inquiry. I've googled/RTFMed. I run mod_perl
> in a reverse proxy setup. Light apache in the front-end, heavy mod_perl
> apache in the back-end both running on the same machine.
>
> The front end has the following reverse proxy directives:
>
> ProxyPass        /perl/ http://localhost:8103/perl/
> ProxyPassReverse /perl/ http://localhost:8103/perl/

You might also want to enbale "ProxyPreserveHost" directive, so that
your backend server can handle virtual servers as well.

Regards,



Jie


> Due to the reverse proxy setup, the original client IP is lost and all IP
> is reported as 127.0.0.1 (front-end). To extract the client's original IP
> I was happy to learn that mod_proxy conveniently adds a X-Forwarded-For
> header to the proxied requests automatically. On the back-end, I use:
>
> PerlPostReadRequestHandler My::ProxyRemoteAddr
>
> where My::ProxyRemoteAddr has code identical to
> http://perl.apache.org/docs/1.0/guide/scenario.html#Usage
> except for some minor mp2 migrations.
>
> sub My::ProxyRemoteAddr ($) {
>     my $r = shift;
>
>     # we'll only look at the X-Forwarded-For header if the requests
>     # comes from our proxy at localhost
>     return Apache::OK
>         unless
>         ($r->connection->remote_ip =~
>          m#^(127\.0\.0\.1|localhost\.localdomain)$#)
>          and $r->header_in('X-Forwarded-For');
>
>     # Select last value in the chain -- original client's ip
>     if( my( $ip ) = $r->headers_in->{'X-Forwarded-For'} =~ /([^,\s]+)$/ )
> {
>         $r->connection->remote_ip($ip);
>         $r->log_error("Recorded client IP from X-Forwarded-For header: ",
>                 $r->headers_in->{'X-Forwarded-For'},
>                 " as IP: ", $ip);
>     }
>
>     return Apache::OK;
> }
>
> Everything is hunky dory. The back-end access_log have the client's IP
> address and the applications sees the correct address as well.
>
> Here's the twist:
>
> To secure the back-end, direct access to the back-end directly is
> prohibited. The back-end config has the following directive to only allow
> proxied requests to come through:
>
> <Location />
>   order deny,allow
>   deny from all
>   allow from localhost 127.0.0.1
> </Location>
>
> If I keep this directive in the back-end config, the client's original IP
> never makes it to the access_log. The application does however get the
> correct IP address.
>
> apache 2.0.47
> mod_perl 1.99_09
> perl 5.8.0
>
> Anyone else experienced the same? Needless to say, I would like to keep
> the site secure, as well maintain the client's original IP in the
> logs.
>
> On second thought, this looks more and more like an apache issue.
> --
> Haroon Rafique
> <ha...@utoronto.ca>
>

Re: Off Topic: mod_perl reverse proxy setup and extracting client's original IP

Posted by Kyle Dawkins <ky...@centralparksoftware.com>.
Ahh hahaha

OK, posted too soon.  Should have read it more carefully.  Sorry to 
post a solution to a problem you don't have. :-)

Kyle Dawkins
Central Park Software

On Thursday, Sep 25, 2003, at 15:05 US/Pacific, Kyle Dawkins wrote:

> Hi there
>
> I have the same setup.  Just put in a rewrite rule to add the client 
> IP into the query string:
>
> RewriteEngine On
> RewriteRule ^/perl/(.*)$ 
> http://localhost:8103/perl/$1?_client_ip=%{REMOTE_ADDR} [P,QSA]
>
> Works like a charm. Then in your mod_perl stuff, you can grab the 
> value of _client_ip from the query string using whichever way you > like.
>
> Cheers
>
> Kyle Dawkins
> Central Park Software
>
> On Thursday, Sep 25, 2003, at 13:15 US/Pacific, Haroon Rafique wrote:
>
>> Hi,
>>
>> I have a slightly off topic inquiry. I've googled/RTFMed. I run 
>> mod_perl
>> in a reverse proxy setup. Light apache in the front-end, heavy 
>> mod_perl
>> apache in the back-end both running on the same machine.
>>
>> The front end has the following reverse proxy directives:
>>
>> ProxyPass        /perl/ http://localhost:8103/perl/
>> ProxyPassReverse /perl/ http://localhost:8103/perl/
>>
>> Due to the reverse proxy setup, the original client IP is lost and 
>> all IP
>> is reported as 127.0.0.1 (front-end). To extract the client's 
>> original IP
>> I was happy to learn that mod_proxy conveniently adds a 
>> X-Forwarded-For
>> header to the proxied requests automatically. On the back-end, I use:
>>
>> PerlPostReadRequestHandler My::ProxyRemoteAddr
>>
>> where My::ProxyRemoteAddr has code identical to
>> http://perl.apache.org/docs/1.0/guide/scenario.html#Usage
>> except for some minor mp2 migrations.
>>
>> sub My::ProxyRemoteAddr ($) {
>>     my $r = shift;
>>
>>     # we'll only look at the X-Forwarded-For header if the requests
>>     # comes from our proxy at localhost
>>     return Apache::OK
>>         unless
>>         ($r->connection->remote_ip =~
>>          m#^(127\.0\.0\.1|localhost\.localdomain)$#)
>>          and $r->header_in('X-Forwarded-For');
>>
>>     # Select last value in the chain -- original client's ip
>>     if( my( $ip ) = $r->headers_in->{'X-Forwarded-For'} =~ 
>> /([^,\s]+)$/ )
>> {
>>         $r->connection->remote_ip($ip);
>>         $r->log_error("Recorded client IP from X-Forwarded-For 
>> header: ",
>>                 $r->headers_in->{'X-Forwarded-For'},
>>                 " as IP: ", $ip);
>>     }
>>
>>     return Apache::OK;
>> }
>>
>> Everything is hunky dory. The back-end access_log have the client's IP
>> address and the applications sees the correct address as well.
>>
>> Here's the twist:
>>
>> To secure the back-end, direct access to the back-end directly is
>> prohibited. The back-end config has the following directive to only 
>> allow
>> proxied requests to come through:
>>
>> <Location />
>>   order deny,allow
>>   deny from all
>>   allow from localhost 127.0.0.1
>> </Location>
>>
>> If I keep this directive in the back-end config, the client's 
>> original IP
>> never makes it to the access_log. The application does however get the
>> correct IP address.
>>
>> apache 2.0.47
>> mod_perl 1.99_09
>> perl 5.8.0
>>
>> Anyone else experienced the same? Needless to say, I would like to 
>> keep
>> the site secure, as well maintain the client's original IP in the
>> logs.
>>
>> On second thought, this looks more and more like an apache issue.
>> --
>> Haroon Rafique
>> <ha...@utoronto.ca>
>>
>


Re: Off Topic: mod_perl reverse proxy setup and extracting client's original IP

Posted by Kyle Dawkins <ky...@centralparksoftware.com>.
Hi there

I have the same setup.  Just put in a rewrite rule to add the client IP 
into the query string:

RewriteEngine On
RewriteRule ^/perl/(.*)$ 
http://localhost:8103/perl/$1?_client_ip=%{REMOTE_ADDR} [P,QSA]

Works like a charm. Then in your mod_perl stuff, you can grab the value 
of _client_ip from the query string using whichever way you like.

Cheers

Kyle Dawkins
Central Park Software

On Thursday, Sep 25, 2003, at 13:15 US/Pacific, Haroon Rafique wrote:

> Hi,
>
> I have a slightly off topic inquiry. I've googled/RTFMed. I run 
> mod_perl
> in a reverse proxy setup. Light apache in the front-end, heavy mod_perl
> apache in the back-end both running on the same machine.
>
> The front end has the following reverse proxy directives:
>
> ProxyPass        /perl/ http://localhost:8103/perl/
> ProxyPassReverse /perl/ http://localhost:8103/perl/
>
> Due to the reverse proxy setup, the original client IP is lost and all 
> IP
> is reported as 127.0.0.1 (front-end). To extract the client's original 
> IP
> I was happy to learn that mod_proxy conveniently adds a X-Forwarded-For
> header to the proxied requests automatically. On the back-end, I use:
>
> PerlPostReadRequestHandler My::ProxyRemoteAddr
>
> where My::ProxyRemoteAddr has code identical to
> http://perl.apache.org/docs/1.0/guide/scenario.html#Usage
> except for some minor mp2 migrations.
>
> sub My::ProxyRemoteAddr ($) {
>     my $r = shift;
>
>     # we'll only look at the X-Forwarded-For header if the requests
>     # comes from our proxy at localhost
>     return Apache::OK
>         unless
>         ($r->connection->remote_ip =~
>          m#^(127\.0\.0\.1|localhost\.localdomain)$#)
>          and $r->header_in('X-Forwarded-For');
>
>     # Select last value in the chain -- original client's ip
>     if( my( $ip ) = $r->headers_in->{'X-Forwarded-For'} =~ 
> /([^,\s]+)$/ )
> {
>         $r->connection->remote_ip($ip);
>         $r->log_error("Recorded client IP from X-Forwarded-For header: 
> ",
>                 $r->headers_in->{'X-Forwarded-For'},
>                 " as IP: ", $ip);
>     }
>
>     return Apache::OK;
> }
>
> Everything is hunky dory. The back-end access_log have the client's IP
> address and the applications sees the correct address as well.
>
> Here's the twist:
>
> To secure the back-end, direct access to the back-end directly is
> prohibited. The back-end config has the following directive to only 
> allow
> proxied requests to come through:
>
> <Location />
>   order deny,allow
>   deny from all
>   allow from localhost 127.0.0.1
> </Location>
>
> If I keep this directive in the back-end config, the client's original 
> IP
> never makes it to the access_log. The application does however get the
> correct IP address.
>
> apache 2.0.47
> mod_perl 1.99_09
> perl 5.8.0
>
> Anyone else experienced the same? Needless to say, I would like to keep
> the site secure, as well maintain the client's original IP in the
> logs.
>
> On second thought, this looks more and more like an apache issue.
> --
> Haroon Rafique
> <ha...@utoronto.ca>
>