How can LocationMatch and ProxyPassMatch be Combined? - apache

I am setting up an Apache 2.4.6 server on an internal machine for testing purposes. One of the things that Apache server is supposed to do is act as a reverse-proxy for another server found on localhost:3030.
The server on localhost:3030 expects one out of a few dataset names on its first path level (for now, the set comprises only of the dataset experimental, but some more will be added later on), so I am trying to pass that through from the requested path.
In my vhost, this works:
<Location /experimental/>
ProxyPass http://localhost:3030/experimental/
ProxyPassReverse /
</Location>
For additional datasets, I could copy that and replace experimental with the other dataset names. Obviously, that leads to a lot of code duplication/redundancy, which is both a source of errors and a maintenance horror.
Therefore, I would like to become somewhat more flexible and treat several datasets in a single such block. This should be possible with the LocationMatch directive.
As indicated by this comment and this page, I need to replace ProxyPass ProxyPassMatch when using that inside a LocationMatch block. Essentially, the docs state the same:
The same will occur inside a LocationMatch section, however ProxyPass does not interpret the regexp as such, so it is necessary to use ProxyPassMatch in this situation instead.
The LocationMatch docs explain:
From 2.4.8 onwards, named groups and backreferences are captured and written to the environment with the corresponding name prefixed with "MATCH_" and in upper case. This allows elements of URLs to be referenced from within expressions and modules like mod_rewrite. In order to prevent confusion, numbered (unnamed) backreferences are ignored. Use named groups instead.
That information is only valid as of Apache 2.4.8, which is presumeably why the following does not work on my 2.4.6 installation:
<LocationMatch /(?<dataset>experimental)/>
ProxyPassMatch http://localhost:3030/%{env:MATCH_DATASET}/
ProxyPassReverse /
</LocationMatch>
On the other hand, this page and that posting imply that the numerical group index ($1) can be used (as the help text is valid only as of httpd 2.4.8, my suspicion / hope is that the numerical reference works before 2.4.8 (?)
In any case, I have tried this:
<LocationMatch "/(experimental)/">
ProxyPassMatch http://localhost:3030/$1/
ProxyPassReverse /
</LocationMatch>
yet according to the logs, the internal call invokes http://localhost:3030/$1/ instead of http://localhost:3030/experimental/ when requesting the experimental path on the vhost URL.
The ProxyPassMatch docs only say:
When used inside a LocationMatch section, the first argument is omitted and the regexp is obtained from the LocationMatch.
However, the text does not bother to provide an example for how to combine LocationMatch and ProxyPassMatch. What am I doing wrong?

The doc also states When the URL parameter doesn't use any backreferences into the regular expression, the original URL will be appended to the URL parameter., which seems to be your case.
Further more, you are missing the host in your ProxyPassReverse directive.
This should work just fine:
<LocationMatch "^/experimental/.*$">
ProxyPassMatch http://localhost:3030
ProxyPassReverse http://localhost:3030
</LocationMatch>

Got this working on Apache 2.4.29:
<LocationMatch "/fruit/(?:apple|banana|pear)">
ProxyPass http://localhost:8080
ProxyPassReverse http://localhost:8080
</LocationMatch>
The URL called by Apache is for example
http://localhost:8080/fruit/apple
The (?: is crucial when you are using parentheses in this example.

Related

How to rewrite url in html document in Apache

What I try to achieve is to rewrite
http://www.mydomain.com/subject/
to
http://mylocalhost:8080/ (= tomcat).
Purely for forwarding I use in httpd:
ProxyPass /subject/ http://mylocalhost:8080/
ProxyPassReverse /subject/ http://mylocalhost:8080/
This works, except for the content of the html documents. IOW: all the links in the returned html still contain
http://mylocalhost:8080/...
My attempts with mod_rewrite haven't been very successful, so my question is: how do I rewrite the actual document contents?
The tomcat app doesn't give the possibility to alter the baseurl.
You may need to do an internal = not visible redirect. Go here for a clean explanation.
For situations where you need to reverse-proxy an application that doesn't cooperate and cannot be updated, there is mod_proxy_html.
This will buffer any returned HTML documents and rewrite links inside them.
ProxyPass /subject/ http://mylocalhost:8080/
ProxyPassReverse /subject/ http://mylocalhost:8080/
ProxyHTMLEnable On
It has various other directives to control precisely what and how it changes.

How to use environment variable from mod_rewrite for interpolate proxypass in httpd.conf

I'm using apache 2.4 and trying to use environment variable inside conf file for proxy pass. There's a thread [Apache proxypass using a variable URL with interpolate ]talking about this:
RewriteEngine on
RewriteMap lowercase int:tolower
#This sets the variable to env:
RewriteRule ^ - [E=SERVER_NAME:${lowercase:%{SERVER_NAME}}]
#Now interpolate makes variables available for proxypass & proxypassreverse:
ProxyPassInterpolateEnv On
ProxyPass / ajp://${SERVER_NAME}:8009/ interpolate
ProxyPassReverse / ajp://${SERVER_NAME}:8009/ interpolate
But when I tried this myself, I get a "AH00111: Config variable ${SERVER_NAME} is not defined" error. Which means Apache2.4 treats the ${SERVER_NAME} as config variable, rather than environment variable.
I also tried using the mod_rewrite sytax for the variable, like this,
ProxyPass / ajp://%{ENV:SERVER_NAME}:8009/ interpolate
ProxyPassReverse / ajp://%{ENV:SERVER_NAME}:8009/ interpolate
But %{ENV:SERVER_NAME} was treated as plaintext string, and created an error since it's not a valid URL pass.
Config variables are defined with "Define" block at server launch. What I want is to have the SERVER_NAME changing at runtime using mod_rewrite.
I can't use the mod_rewrite [P] argument, since I need to have the ProxyPassReverse block working with variable as well. mod_rewrite can't deal with rewriting the response, and therefore can't mimic the function of ProxyPassReverse.
Any ideas on how to use environment variable in interpolate proxypass conf directives?
It turns out Apache will still load and work fine, even with the warnings, using this syntax:
ProxyPassReverse / ajp://${SERVER_NAME}:8009/ interpolate
This issue was identified in this mailing list thread. The discussion is about another issue, but they mention this problem and discuss the idea of adding a second interpolation syntax to ProxyPass, etc. However, I have not found a bug report, and it seems as of Apache 2.4.10, the mod_proxy code still supports only the ${varname} syntax, which conflicts with the overall httpd.conf interpolation.
I haven't found a way to disable those specific warnings, but if you are willing to live with the warnings, Apache should still work for you.
One caveat is that if there is a system environment variable present with the same name when Apache is loading, it will overwrite the value you are trying to interpolate at runtime.

conditional proxypass ajp rules using ip whitelist

I've successfully created a ProxyPass ajp rule which works fine, but now i want to restrict the access of certain urls using an ip-whitelist. In other words, when someone comes from an ip that is not on the whitelist the request should not be proxypassed (and, ideally, some sort of access denied should be issued)
i don't have control over the machine i'm proxy-passing to, so i can't put the ip-whitelist on that machine's configuration. That's why i'm trying to configure this on the same machine that has the proxypass rule.
Defining a <Location /path> with 'Allow from'-rules doesn't work, because the request is still proxypassed. I guess this simply means the proxypass rules preceed the location-rules.
I've tried to work around it by setting an environment variable depending on the remote-address (because then i could proxy non-whitelist-ips to nonexistent url - not pretty, but it would achieve the goal), but it seems the proxypass rule doesn't work with environment variables. Something as simple as this:
SetEnv custom_proxypath=/
ProxyPass %{ENV:custom_proxypath} ajp://10.50.40.21:8009/
ProxyPassReverse %{ENV:custom_proxypath} ajp://10.50.40.21:8009/
doesn't work. while
ProxyPass / ajp://10.50.40.21:8009/
ProxyPassReverse / ajp://10.50.40.21:8009/
works perfectly.
I'm out of options. Does anyone else have a suggestion how to approach this?
I learned this today.... SetEnv is applied later in the request cycle than the ProxyPass, so it isn't set in time. However, SetEnvIf is applied early enough, as are environment variables set with RewriteCond/RewriteRule. You should be able to refactor this to a SetEnvIf that is always true and that will do the trick.

Apache mod_rewrite mod_proxy redirect

I am trying to redirect /foreman to https://someurl:4343
I am using:
SSLProxyEngine on
ProxyPass /foreman https://MyIP:4343/
ProxyPassReverse /foreman https://MyIP:4343/
Results so far are that:
I get the index page with no style and no images
none of the links work i.e. /foreman/hosts?somevariable=somevalue
I would like to get all requests to /foreman/* to go to https://MyIP:4343/* including variables, get requests, images, style sheet, etc
How should I proceed ?
This was a clueless noob moment.
I found out that my desired outcome can be resolved with mod_ruby
I used the below link for a guide to the resolution to my issue.
Foreman as Sub-URI
You need the trailing slash on /foreman
ProxyPass /foreman/ https://MyIP:4343/
ProxyPassReverse /foreman/ https://MyIP:4343/

Reverse Proxy in CakePHP?

I've got a CakePHP application, and the following directives in my httpd.conf
ProxyRequests off
ProxyPass /forum/ http://somesite.com/phpbb3
ProxyPass /gallery/ http://someothersite.com/gallery3
<Location /forum/>
ProxyPassReverse /
</Location>
<Location /gallery/>
ProxyPassReverse /
</Location>
Without CakePHP this works fine - but because CakePHP is using it's own redirection logic from routes.php and other sources, it seems to override any proxy settings, so any call to "/community" on my server follows the default pathway of looking for a Controller called CommunityController.
My issue here is that I want to have one server that serves muliple applications, but keep it seamless to the user - so a complete PHPBB application can for instance run within the "/forum" directory as if it were a controller in CakePHP.
Has anyone done this before, and can it be done? Why does mod_rewrite and/or the routes.php file override my mod_proxy directives??
Perhaps instead of using mod_proxy, you could use mod_rewrite to create a RewriteRule directive with the [P] (proxy) flag in conjunction with the [L] (last rule) flag.
'proxy|P' (force proxy):
This flag
forces the substitution part to be
internally sent as a proxy request and
immediately (rewrite processing stops
here) put through the proxy module.
You must make sure that the
substitution string is a valid URI
(typically starting with
http://hostname) which can be handled
by the Apache proxy module. If not,
you will get an error from the proxy
module. Use this flag to achieve a
more powerful implementation of the
ProxyPass directive, to map remote
content into the namespace of the
local server.
Note: mod_proxy must be enabled in
order to use this flag.
'last|L' (last rule):
Stop the
rewriting process here and don't apply
any more rewrite rules. This
corresponds to the Perl last command
or the break command in C. Use this
flag to prevent the currently
rewritten URL from being rewritten
further by following rules. For
example, use it to rewrite the
root-path URL ('/') to a real one,
e.g., '/e/www/'.