ProxyPass ! directive not working - apache

I am in the middle of migrating a server and my old virtual host config was like this
ProxyPass /images !
ProxyPass / ajp://domain.tld:8010/ nocanon
It passes ok to Tomcat but the ! directive is being ignored. There are no errors thrown. What might be causing this?

If the /images rule matches but the path is not valid, e.g. cannot be found, Apache will try the next rule.
Only if all other rules are failing too, the first matched rule is used (and the corresponding error is shown, e.g. 404 instead of proxy error).

Related

ProxyPass Exclude path

i configured an apache proxy to forward all calls to another web server. I need to exclude the path http://my-server/{var1}/api/{all-path} (where var1 is variable) from this rule.
How can I do?
Thanks
I tried with:
ProxyPassMatch ^/(.*)/api/(.*)$ !
ProxyPass / http://127.0.0.1:8080/
but not working.
I'd say you need a negative lookahead in your matching pattern and only a single proxy directive:
ProxyPassMatch ^/[^/]+/(?!api/) http://127.0.0.1:8080/
That should match any path starting with something and a following slash, followed by anything that is NOT "api/".

Apache proxy different context path cookie issue

I'm currently developing an application that will be deployed in a Docker container. The Docker contains a Tomcat that runs the application as ROOT.war, so at top level.
The idea is that when our users run the container, they may want to run several copies on a specific context path on their servers each, so for example:
https://somedomain.com/a and https://somedomain.com/b
My plan was to simply tell them to configure a proxy reverse like this:
ProxyPreserveHost On
RewriteEngine On
# Map https://somedomain/a to http://internalserver:9001
RewriteRule ^/a$ /a/ [R]
ProxyPass /a/ http://internalserver:9001/
ProxyPassReverse /a/ http://internalserver:9001/
# Map https://somedomain/b to http://internalserver:9002
RewriteRule ^/b$ /b/ [R]
ProxyPass /b/ http://internalserver:9002/
ProxyPassReverse /b/ http://internalserver:9002/
Where 9001 and 9002 are the ports of the two Docker containers running copies of my application.
Now, this makes the application run, but there are issues with cookies, as the context path on the server in Tomcat is always empty and therefore there are session issues.
I've seen several questions about similar situations, but in all cases, people are able to either change the public path or the path within Tomcat to make them match. In my case, I simply cannot do that, because I'd be dictating which path the users of our software would have to use.
Here are examples of such questions:
https://serverfault.com/questions/311994/how-to-proxy-context-to-different-backend-context-in-apache
https://serverfault.com/questions/495017/how-do-i-ensure-the-context-path-is-the-same-when-accessing-a-web-app-via-apache
Tomcat behind an apache proxy error on path
Is there any way to make this setup work properly?
Can I change the proxy configuration to forward the context path somehow?
Are there other options?
Ok, I found a quite simple solution. Maybe it'll help someone else, so I'll post it here:
I figured out that there's a proxy config option called ProxyPassReverseCookiePath which is meant to be used for exactly what I was trying to achieve, so I changed the config to this:
RewriteRule ^/a$ /a/ [R]
<Location /a/>
ProxyPass http://internalserver:9001/
ProxyPassReverse http://internalserver:9001/
ProxyPassReverseCookiePath / /a
</Location>
RewriteRule ^/b$ /b/ [R]
<Location /b/>
ProxyPass http://internalserver:9002/
ProxyPassReverse http://internalserver:9002/
ProxyPassReverseCookiePath / /b
</Location>
This maps every cookie path coming from the internal server with a path of / to /a or /b depending on the application, which is exactly what I wanted. The application itself now always sets the cookie path to just / if there is no context path available. The reverse proxy then maps it back to wherever it was requested from.

Apache ProxyPass error

I have to redirect all apache requests on 80 to tomcat on 8080, except one path.
So, if a receive http://example.com/anything --> tomcat:8080.
But, if the url is that: http://example.com/site --> apache should serve and no redirect is needed.
Currently, there is a folder named site inside /var/www/html/.
This is my current configuration file:
site.conf (this file contains only the following and is inside the conf.d folder)
<LocationMatch "/*">
Allow from all
ProxyPass /site !
ProxyPass http://127.0.0.1:8080
ProxyPassReverse http://127.0.0.1:8080
</LocationMatch>
I think this is a simple thing to accomplish with apache, but I have tried everything that I could find and I am still getting the error:
ProxyPass|ProxyPassMatch can not have a path when defined in a location.
The thing is that the root website is running on tomcat, but the other runs on apache (the one that I called site in this question).
If anyone can help, I appreciate.
Thanks!
Update 1 - 09/06/2017
I get it to work if I remove the LocationMatch and put the ProxyPass
direct in the .conf file:
ProxyPass /site !
ProxyPassReverse /site !
ProxyPass / http://127.0.0.1:8080
ProxyPassReverse / http://127.0.0.1:8080
But, I would like to know, why is that? What is the impact of putting this directives outside the LocationMatch tag? And, most important, why I cannot accomplish the same result using the LocationMatch?
I think the error is pretty clear:
ProxyPass|ProxyPassMatch can not have a path when defined in a location.
According to the documentation, inside a context block like Location or LocationBlock the ProxyPass directive does not accept a path:
When used inside a <Location> section, the first argument is omitted and the local directory is obtained from the <Location>. 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.
You're getting the error because you were trying to use a path:
ProxyPass /site !
You could try to resolve this in theory by using multiple <Location> sections, like this:
<Location />
ProxyPass http://backend/
</Location>
<Location /site>
ProxyPass !
</Location>
The ordering of these sections is important.
Your solution of using ProxyPass directives outside of a LocationMatch block is probably the simplest solution.
As a side note, your LocationMatch directive is incorrect. The argument to LocationMatch is a regular expression, and /* would only match URLs consisting only of / characters. That is, it would match / or // or /////////, etc. I think you really meant /.*. The * in a regular expression means "the previous character, zero or more times".

How to server static files + proxy context

I am wondering how to configure my httpd server to serves the following pages:
My need is to serve static content located in my /var/www/static when url is /context/static and to proxy the remaining to a tomcat server
In this order:
/context/static/* --> files served by httpd
/context/* --> resources served by tomcat
I have tried to rewrite /context/static/* to a folder pointing to my /var/www/static and added the ProxyPath directive for the remaining but I can't get it working.
What are the best practices and how to achieve that ?
Thanks in advance
Well, in fact it is quiet easy...
Having such folders configured:
/var/www/static/
|- css/*
|- js/*
\ medias/*
The following httpd configuration will redirect static/* to the /var/www and the rest will be proxied
# first rewrite for statics
RewriteEngine On
RewriteRule ^/context/static/(.+)$ /static/$1
# then proxy remaining...
ProxyPass /context http://127.0.0.1:8080/context
ProxyPassReverse /context http://127.0.0.1:8080/context
I've found the following approach that works and is quite general. (4/12/2018)
Location/Proxypass expressions always take priority over any other location block, so you have to Exclude the paths that you don't want to be proxied. the "?!" does that in the regex. Since static content is, um, static, it is not so bad to require that the apache configuration be updated if another directory is needed to be served directly for a different media type.
The following was taken from a server that was proxying a Python Flask application.
<LocationMatch "^/(?!js|css|media)" >
ProxyPass http://127.0.0.1:5000
ProxyPassReverse http://127.0.0.1:5000
</LocationMatch>
<Location "/">
Require all granted
</Location>
Both of the existing answers rely on Regular Expressions. While they work, it is possible to do this without such complicated constructs. ProxyPass can take "!" as a second parameter, in which case it doesn't proxy the matching URL. For example
ProxyPass /context/static/ !
ProxyPass /context http://127.0.0.1:8080/context
ProxyPassReverse /context http://127.0.0.1:8080/context
or, with multiple exclusions,
ProxyPass /js !
ProxyPass /css !
ProxyPass /media !
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
These exceptions need to come before the more general rule in order to take precedence.
Thanks to freenode user "thumbs" in #httpd.

Stuck with apache,mod-ajp weird redirection

hi all i have a redirection problem with mod ajp, that it always adds the application name before the desired page, for example:
if i requested the page:
http://myapp.com/mypage
it is converted to
http://myapp.com/myapp/mypage, and i get a 404 error
i don't know why such behaviour occurs, this is the configuration:
<Proxy *> AddDefaultCharset Off Order deny,allow Allow from all </Proxy>
ProxyPass / ajp://127.0.0.1:8009/myapp/
ProxyPassReverse /
ajp://127.0.0.1:8009/myapp/
ProxyPassReverseCookiePath /myapp/
this strange redirection occurs exaclty when an inside application redirection occurs meaning after registration the user is redirected(application side) to the login page using response.sendRedirect , any ideas ?
The ProxyPassReverse directive is possibly wrong. I guess it should be
ProxyPassReverse / http://myapp.com
See The Mystery of ProxyPassReverse.
You can resolve problems like this with this approach:
Install LiveHTTPHeaders and enable it
Access the application directly
Access the application via your reverse proxy
Compare the HTTP traffic of the previous cases
Most likely your application redirects user using relative URL. However your ProxyPassReverse only rewrites absolute versions. The relative version gets redirected with the page load according to your ProxyPass rule, causing the doubling of the path.