Tomcat mod_proxy AJP static resources directory - apache

I am using httpd with tomcat using the following config:
ProxyPass / ajp://localhost:8009/MyProject
ProxyPassReverse / ajp://localhost:8009/MyProject
This works fine except my image links from tomcat do not work when the HTML renders:
<img src="/MyProject/img/image.jpg"/>
where as I would expect:
<img src="/img/image.jpg"/>

Your image(s) is placed in tomcat at path /img/image.jpg that is context relative path, the absolute path is /MyProject/img/image.jpg for your tomcat, eventhough it is /img/image.jpg outside of the apache. You proxy / -> /MyProject so when you add the context name to the path 'MyProject', it really doesn't work as you mentioned.
SOLUTION 1:
Use context relative paths in tomcat
img/image.jpg
In this case you have to be careful about the requrested URI, e.g. /MyProject/page1/action1/ has its image relative path
../../img/image.jsp
SOLUTION 2:
Use document root paths with leading slash
/img/image.jpg
and define the element base with the document root ('href' attribute). Just be careful about link!
<head>
<base href="http://www.mydomain.com/">
</head>
see http://www.w3schools.com/tags/tag_base.asp
SOLUTION 3:
Map the project to the same URI in apache as in tomcat (Personaly I use this solution as well because it is very easy, and I use a common word as a project/context name, e.g. 'web', 'site', etc.).
ProxyPass /MyProject ajp://localhost:8009/MyProject
SOLUTION 4:
Use a content filter such as mod_proxy_html
http://httpd.apache.org/docs/current/mod/mod_proxy_html.html
NOTE: This solution is ever a bit slow (it doesn't matter witch filter you use)!
Be aware PROXY CONFIGURATION!!!
This is just about redirect etc., but you have a wrong configuration of your ProxyPathReverse!
ProxyPass / ajp://localhost:8009/MyProject
ProxyPassReverse /MyProject http://www.mydomain.com/
see the full explanation
http://www.humboldt.co.uk/the-mystery-of-proxypassreverse/#more-131
read configuration examples
http://www.apachetutor.org/admin/reverseproxies

You need to either:
Use mod_html to rewrite the links. This is slow, and an indication that you've done the wrong thing.
Issue a redirect from / to /MyProject, which you can do with a RewriteRule, or a <meta http-equiv="refresh" content="0; url=http://<host>/MyProject/"> in /index.html, and change the ProxyPass directives to
ProxyPass /MyProject ajp://localhost:8009/MyProject
so that proxying doesn't mess around with the URL paths. This is by far the better technique. You probably don't need the ProxyPassReverse directive at all, but if you do you should apply the same change.

I have not yet tested this for accuracy (and AJP tends to short circuit things like rewrites in Apache making extra testing and tweaking almost mandatory). So with that little AJP-disclaimer you might try something along the lines of:
ProxyPass /MyProject ajp://localhost:8009/MyProject
ProxyPassReverse /MyProject ajp://localhost:8009/MyProject
ProxyPass / ajp://localhost:8009/MyProject
ProxyPassReverse / ajp://localhost:8009/MyProject
Just to try catching those incorrect image paths on the inbound. If that fails try toying with a trailing slash.

Related

Apache Reverse Proxy Sending Browser to Backend Directly Instead

(UPDATE at the bottom for the main question, below may be superfluous details)
I'm having an interesting problem with Apache not reverse proxying as expected.
Basically, what's happening is when I click a link on my website that goes to the relative path /app1, I am expecting it the URL to be external.company.ca/app1 with content coming from internal.company.ca/some_app. Instead, the browser is going directly to internal.company.ca/some_app.
No 302 or anything, just straight there. This is odd to me, since internal.company.ca is not mentioned anywhere in the configuration except for the reverse proxy config, so I don't know how the browser is learning of the domain at all.
Here is a Fiddler capture from the client (browser) point of view showing the behaviour right after I click the link that goes to /app1 (you'll have to trust me that the green names are external.company.ca and the black names are internal.company.com and the path is /some_app/blahblah):
Everything happening after this point is loading the page with internal.company.com. This won't work at all in production, of course.
The following is a (truncated) version of our Apache configuration files for consideration:
<VirtualHost *:80>
# rewrite rules to 443
</VirtualHost>
<VirtualHost *:443>
ServerName external.company.ca
ServerAlias external.company.com
# Logging rules.........
SSLEngine on
SSLProxyEngine on
SSLProxyVerify none
# Most of this is off for testing purposes, adding in case it matters
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
# more SSL stuff.... Now on to the interesting part
ProxyPreserveHost On
ProxyPass /app1 https://internal.company.com/some_app
ProxyPassReverse /app1 https://internal.company.com/some_app
</VirtualHost>
At one point, I thought that possibly the cookies were throwing things off since they were under different domains (.ca in front, .com in back), but I believe if the reverse proxying was working correctly, the browser would be none the wiser. Anyone see anything wrong with the above?
UPDATE
I found the culprit:
<script type="text/javascript">window.location.assign('https://internal.company.com/app1/login?redirectUrl=' + encodeURIComponent(window.location.pathname + window.location.hash));</script>
The problem is, how do I rewrite this absolute URL using Apache? I know mod_proxy_html modifies element attributes (such as href in the a element) but can it rewrite arbitrary data in an element itself?
The internal application was provided by a vendor, and although it may be possible to make modifications to it to remove code like the above, I would prefer to stay away from that path for now to see if there are alternatives.
I've come up with a somewhat nasty work-around:
ProxyHTMLEnable On
ProxyHTMLExtended On
ProxyHTMLLinks script src
ProxyHTMLURLMap https://internal.company.com
The problem is the use of absolute URL's throughout the HTML (and javascript) coming from the vendor's app. A search and removal of the domain solves the problem (but is incredibly slow).
If anyone has this problem in the future, I do not recommend using this solution. I'm guessing you're here because you can't modify the internal application. You should instead be sending in a ticket to whoever maintains the code to make their application more reverse-proxy friendly.
A potentially safer solution would be the use of mod_substitute. You could also consider ProxyHTMLExtended, but it can be quite brutal in its replacements, occasionally breaking JavaScript here and there.
Edit: Just noticed you're currently using ProxyHTMLExtended. My bad. As you've highlighted it is a pretty brutal and dangerous solution to the problem.

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.

Apache ProxyPassReverse values

our IT is trying to configure a new apache/jboss/apj setup.
When I browse to http://domain.com/jboss/test.jsp
and System.out.println request.getRequestURL()
I get http://domain.com/test.jsp
(without jboss)
My app encounteres a lot of 404's because of this.
The IT department said Jboss has no concept of the /jboss/ part of the url because of the proxy. Are they configuring things properly or do I need to change my code. To me my code is not portable if I have to hard code url paths.
Edit-
Here is what they told me:
<Location /jboss>
ProxyPass balancer://cluster stickysession=JSESSIONID
ProxyPassReverse https://domain.com/jboss/
</Location>
This article supports my question
https://sosiouxme.wordpress.com/2010/08/18/fixing-apache-httpd-reverse-proxy-redirect-rewrites/
Edit2
On our old server in a my login framework servlet used by a few apps I had
response.sendRedirect("login.jsp?message=You have successfully logged off.");
to get things to work with the new proxy I have to recode as
response.sendRedirect("/jboss/AppName/login.jsp?message=You have successfully logged off.");
I lose portablity and reuseabilty with the latter syntax.
The error (in Apache, not jboss) for
response.sendRedirect("login.jsp?message=You have successfully logged off.");
File does not exist: /WEB/wwwssl/AppNamelogin.jsp
Note there is no "/" between my appname and login.jsp
The error (in Apache, not jboss) for
response.sendRedirect("/login.jsp?message=You have successfully logged off.");
File does not exist: /WEB/wwwssl/login.jsp
Note the AppName is missing
Note that the article you mention uses mod_proxy_html (ProxyHTMLURLMap ProxyHTMLURLMap / /ajp/nocluster/), which will fix links to use the right path prefix. This is not part of the default mod_proxy modules provided with Apache Httpd.
Instead of putting these directives in a <Location> block, using a single line syntax might forward the path correctly:
ProxyPass /jboss balancer://cluster stickysession=JSESSIONID

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/

Apache - Reverse Proxy and HTTP 302 status message

My team is trying to setup an Apache reverse proxy from a customer's site into one of our web applications.
http://www.example.com/app1/some-path maps to http://internal1.example.com/some-path
Inside our application we use struts and have redirect = true set on certain actions in order to provide certain functionality. The 302 status messages from these re-directs cause the user to break out of the proxy resulting in an error page for the end user.
HTTP/1.1 302 Found
Location: http://internal.example.com/some-path/redirect
Is there any way to setup the reverse proxy in apache so that the redirects work correctly?
http://www.example.com/app1/some-path/redirect
There is an article titled Running a Reverse Proxy in Apache that seems to address your problem. It even uses the same example.com and /app1 that you have in your example. Go to the "Configuring the Proxy" section for examples on how to use ProxyPassReverse.
The AskApache article is quite helpful, but in practice I found a combination of Rewrite rules and ProxyPassReverse to be more flexible. So in your case I'd do something like this:
<VirtualHost example>
ServerName www.example.com
ProxyPassReverse /app1/some-path/ http://internal1.example.com/some-path/
RewriteEngine On
RewriteRule /app1/(.*) http://internal1.example.com/some-path$1 [P]
...
</VirtualHost>
I like this better because it gives you finer-grained control over the paths you're proxying for the internal server. In our case we wanted to expose only part of third-party application. Note that this doesn't address hard-coded links in HTML, which the AskApache article covers.
Also, note that you can have multiple ProxyPassReverse lines:
ProxyPassReverse / http://internal1.example.com/some-path
ProxyPassReverse / http://internal2.example.com/some-path
I mention this only because another third-party app we were proxying was sending out redirects that didn't include their internal host name, just a different port.
As a final note, keep in mind that Firebug is extremely useful when debugging the redirects.
Basically, ProxyPassReverse should take care of rewriting the Location header for you, as Kevin Hakanson pointed out.
One pitfall I have encountered is missing the trailing slash in the url argument. Make sure to use:
ProxyPassReverse / http://internal1.example.com/some-path/
(note the trailing slash!)
Try using the AJP connector instead of reverse proxy. Certainly not a trivial change, but I've found that a lot of the URL nightmares go away when using AJP instead of reverse proxy.