Apache Reverse Proxy Sending Browser to Backend Directly Instead - apache

(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.

Related

ProxyHTMLURLMap not rewriting URLs the right way

I have a Web-IRC-Client (The Lounge) running at http://www.example.com:3000/ (no HTTPS) and visiting the link works fine. When I specify the port I can use the Web-Client without any problems. Now, I don't want to type the port every time and that's why I am trying to setup a reverse proxy using Apache2's configuration file. The problem is that the client is loading the assets (CSS, JS, images) from the wrong location. See below for more info. I think ProxyHTMLURLMap is the right way of fixing it, but cannot get it to work. I should also note, that I am redirecting all non-www-http traffic to the www-https version.
<VirtualHost *:443>
[...]
SSLProxyEngine on
ProxyPass /irc http://www.example.com:3000/
ProxyPassReverse /irc http://www.example.com:3000/
ProxyHTMLURLMap http://www.example.com:3000/ /irc
</VirtualHost>
When I visit https://www.example.com/irc I just get the text of the website with my javascript, css, etc. Checking the source code reveals, that it is trying to load the assets from:
https://www.example.com/css/bootstrap.css
Which is wrong. It should, instead, be loading from:
https://www.example.com/irc/css/bootstrap.css
Any advice would be greatly appreciated!
EDIT 1: Some more info: Browsing to the https proxy with a slash at the end (https://www.example.com/irc/) kind of works. The images and CSS get loaded, but the client itself doesn't respond and shows "This is taking longer than it should, there might be connectivity issues." even though everything is up.
EDIT 2: Another user suggested adding ProxyHTMLExtended On, but it didn't help either.
Even though this question is very old, I want to leave this here:
https://serverfault.com/a/685326
Note:
If it's still not working, you might add to your config:
ProxyHTMLEnable On

How to set up a seamless proxy in Apache to get around my ISP's firewall?

I'm really hoping someone can help me out with this because I've been at it for several days and I think I'm going crazy!
I'm trying to do what to me sounds like a stupidly simple thing. I want to set up a proxy server using Apache on a dedicated machine that I rent so that I can get around my ISPs nonsense firewall. I am aware that I could use a VPN, I don't want to do that for reasons that should hopefully become clear after I explain the details of what I want.
First of all, I don't want the proxy server to be used for every request. Only for the sites that are blocked by my ISP.
Suppose I try to access blockedsite.com/path/to/resource and it fails. I then simply want to change the URL in the address bar to proxy.myserver.com/proxy/blockedsite.com/path/to/resource and have Apache handle everything to provide me with a seamless experience. That means,
ProxyPassReverse should modify the response headers to use to the proxy server.
All URLs in the response body should be modified to use the proxy
Here's what I have so far:
<VirtualHost *:80>
ServerName proxy.myserver.com
ProxyRequests off
ProxyPass /proxy/ http://
ProxyPassReverse /proxy/ http://
ProxyPassReverse /proxy/ https://
ProxyHTMLURLMap http:// /proxy/
ProxyHTMLURLMap https:// /proxy/
<Location /proxy/>
ProxyPassReverse /
AddOutputFilterByType SUBSTITUTE text/html
Substitute "s|</title>|</title><meta name='referrer' content='no-referrer' />|ni"
ProxyHTMLEnable On
#ProxyHTMLURLMap / /app1/
RequestHeader unset Accept-Encoding
Order allow,deny
Allow from all
</Location>
</VirtualHost>
This setup works beautifully for URLs that don't try to redirect me elsewhere. But if for example I try to access proxy.myserver.com/proxy/facebook.com I am still being redirected on the client side to https://www.facebook.com instead of https://proxy.myserver.com/proxy/www.facebook.com as I would like. The extra weird thing is that when I set up my own test site which does nothing except redirect me to an HTTPS address, the ProxyPassReverse rule for HTTPS does actually seem to work... but not when I try to access sites like Facebook or Google.
I see no reason to ramble on about my issues, what I'm looking for is astoundingly simple: a transparent, seamless experience! Aside from sticking proxy.myserver.com/proxy/ in front of the URL in the address bar, I shouldn't have to do anything else for it to work. Yet that is not the case and despite over a week of searching, I have found nothing online to help me with this. It's as if I'm the only person in the universe to want to create a simple proxy with Apache that actually works as a firewall-get-arounder.
Please can someone lend me a hand here?! Even just to tell me I'm going about this all wrong and should give up and install Squid or something??
Your last paragraph contains the right answer. You should indeed just "install Squid or something". In particular, I'd recommend Apache Traffic Server - http://trafficserver.apache.org/ - this is exactly what it's made for.
While Apache httpd can do proxying, it's not it's primary function, and so there are always things that will end up being frustrating with it. We could get your above scenario working, but it's really not the right tool for the job.

How to make yii2 module load at root level

I'm more of a frontend guy (CSS, javascript) trying to expand my knowledge about backend (apache, proxies) (so try to be gentle) and I'm asking after serveral hours of documentation, trying different approaches but so far nothing worked. I'm aware that I might be oblivious to concepts that go without saying for someone knowing their way around backend.
I have this Yii2 application, with a module, working fine. I would like this module to be available at the root level of another domain, on the same machine.
From everything I've read, the following code, placed in vhosts of my apache, should work:
<VirtualHost *:80>
ServerName buletin
ProxyPass / http://bdc/ik2/frontend/web/buletin/default/
ProxyPassReverse / http://bdc/ik2/frontend/web/buletin/default/
</VirtualHost>
I'm expecting to see the default action of my module when I go to http://buletin.
What am I missing?
Ok, in case someone else has the same problem, just double check all of your app's redirects and make sure everything works inside your module. If it doesn't, either add it as exception to the ProxyPass i.e.:
ProxyPass /ik2/frontend/web/themes/ http://bdc/ik2/frontend/web/themes/
ProxyPass /ik2/frontend/web/img/ http://bdc/ik2/frontend/web/img/
ProxyPass /ik2/frontend/web/assets/ http://bdc/ik2/frontend/web/assets/
#(all exceptions need to be placed above general ProxyPass and ProxyPassReverse)
or make it available inside your module.
In my case, I wasn't logged in the "new" website and it was redirecting me to /site/login, which did not exist (no buletin/default/site/login). Once I handled it and I added the exceptions for the assets and images to the ProxyPass, it's all working smoothly.

Apache2 httpd.conf help

I have a domain, for example, http://example.com. It is already configured to point to
/var/www/
Basically, i want http://example.com to point to
/var/www/4.0/
and http://example.com/foobar/ to point to
/var/www/moo/
How can I do this with the httpd.conf file for Apache2? Thanks
Assuming you are only serving one domain (example.com), you can change your DocumentRoot to /var/www/4.0/
and set an Alias for the /foobar like
Alias /foobar /var/www/moo
If you are serving more than one domain from the same Apache, then you need to use the DocumentRoot within a VirtualHost tag.
More info is here: http://httpd.apache.org/docs/2.2/vhosts/
I think you're going about this the wrong way with httpd.conf, but I'll answer your question as you asked it first and then explain about that.
There are two settings in httpd.conf relevant to this.
The DocumentRoot setting is the important one, it configures the base directory from which to serve. Change it as so:
Before:
DocumentRoot "/var/www"
After:
DocumentRoot "/var/www/4.0"
Be sure not to use any / after the 4.0, it's not needed.
A little under 30 lines below this setting is another, which should say:
As the comment above it says, change it to "/var/www/4.0" too.
This would set www.example.com to the 4.0 directory (first part) and apply the relevant settings to this directory too (second part).
But I don't think you should do that, setting apache to serve the 4.0/ directory with httpd.conf makes a mess for serving the other directories. I'd suggest you read about redirects and how to implement them with whatever language you're using. Then you can point one URL to another without it ever being noticed in the browser (unless they're really trying to).
So without changing DocumentRoot from "/var/www", you can edit /var/www/index.php (or whatever) and have it redirect to /var/www/4.0/. The same can be done in /var/www/foobar/index.php to display /var/www/moo/ instead, but here I'd really just rename the "foobar" directory on the server to "moo". If you want to get elaborate, look into mod_rewrite, but I'd advise you to try all your alternatives first and only use it if you really need to, it's quite a complex tool.

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.