Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly configure a reverse proxy with Apache, to be used for cross-domain AJAX?

Needing to develop a web application that at the same time is highly dependent on an API but at the same time cannot reside on the same domain as the API itself, it's been quite tricky getting around the "Same Origin Policy" when making asynchronous HTTP requests (AJAX). At one point, I was recommended to install WAMP on my computer (running Windows 7) and to configure a reverse proxy with Apache. The same person gave me the Apache directives bellow that I added to the httpd.conf file, after telling me to create an alias for the IP 127.0.0.1 named dev , within the file at c:\windows\system32\drivers\etc\hosts (which I did):

LoadModule headers_module modules/mod_headers.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so

Listen 127.0.0.1:8080
ProxyRequests off

<Proxy *>
                Order deny,allow
                Deny from all
                Allow from 127.0.0.1
</Proxy>

<VirtualHost dev:8080>
                ProxyPass / https://app.somesite.com:5002/
                ProxyPassReverse / https://app.somesitecom:5002/
                ProxyPassReverseCookieDomain app.somesite.com dev
                Header edit Location ^https://dev(:8080)?(.+)$ http://dev$1$2
                Header edit Set-Cookie "(^.+); secure; HttpOnly$" "$1; HttpOnly"
                SSLProxyEngine on
    SSLProxyVerify none
</VirtualHost>

Since I'm a complete novice when it comes to configuring servers, I simply pasted the directives and fortunately enough, the proxy worked. It returns the correct response from the API when I use the browser's address bar to access, for example, http://dev:8080/a/w/currencies.

Unfortunately though, an AJAX request to the same URL (code bellow) makes Chrome give me the XMLHttpRequest cannot load http://dev:8080/a/w/currencies. Origin http://dev is not allowed by Access-Control-Allow-Origin. error.

$.ajax({
    url: "http://dev:8080/a/w/currencies",
    type: "GET",
    dataType: "json",
    data: {

    },
    success: function(data){
        console.log(data);
    }
}); 

So what must still be done in order for this proxy to work with AJAX? I've been told something about an alias directive, but not specific and clear enough, so it didn't make much sense to my inexperienced brain.

PS: Also, I've been told "the problem is that you're getting the files from dev:80 and ajaxing to dev:8080". Given my inexperience, neither this makes much sense.

like image 457
Andrei Oniga Avatar asked Jan 06 '13 19:01

Andrei Oniga


2 Answers

You are having a server with a public IP and apache is running on it.Now you want to host your applications on LAN and also want them to be accessible on internet the important part is these applications are still running on the machines on LAN.

                           |--------------192.168.1.3
                           |            (internal3.example.com)
                           |
                           |--------------192.168.1.4
                           |            (internal4.example.com)
  (Public IP )             |
            A--------------|
(reverse proxy server)     |
  (192.168.1.25)           |
example.com                |
                           |--------------192.168.1.1
                           |            (internal1.example.com)
                           |
                           |--------------192.168.1.2
                           |            (internal2.example.com)

I am using Ubuntu to host Apache the vhost definition in case of Debian based systems the definiton of websites is done on

/etc/apache2/sites-enabled/*.conf

where *conf corresponds to

internal1.conf internal2.conf internal3.conf internal4.conf

The vhost definition of each of these sites will be as follows

/etc/apache2/sites-enabled/internal1.example.conf

<virtualhost *:80>
    ServerAdmin webmaster@localhost
    ServerName internal1.example.com
    ProxyRequests off
    <proxy *>
        Order deny,allow
        Allow from all
    </proxy >
    ProxyPass / http://192.168.1.1/
    ProxyPassReverse / http://192.168.1.1/ 
</VirtualHost>

/etc/apache2/sites-enabled/internal2.example.conf

<virtualhost *:80>
      ServerAdmin webmaster@localhost
      ServerName internal2.example.com
      ProxyRequests off
      <proxy *>
      Order deny,allow
      Allow from all
      </proxy >
      ProxyPass / http://192.168.1.2/
      ProxyPassReverse / http://192.168.1.2/
</VirtualHost >

/etc/apache2/sites-enabled/internal3.example.conf

<virtualhost *:80>
      ServerAdmin webmaster@localhost
      ServerName internal3.example.com
      ProxyRequests off
      <proxy *>
      Order deny,allow
      Allow from all
      </proxy >
      ProxyPass / http://192.168.1.3/
      ProxyPassReverse / http://192.168.1.3/
</VirtualHost >

/etc/apache2/sites-enabled/internal4.example.conf

<virtualhost *:80>
    ServerAdmin webmaster@localhost
    ServerName internal4.example.com
    ProxyRequests off
    <proxy *>
        Order deny,allow
        Allow from all
    </proxy>
    ProxyPass / http://192.168.1.4/
    ProxyPassReverse / http://192.168.1.4/
</VirtualHost>

Note in all of the above vhost definitions I have dropped the options of Log files. So if you apply to a production server add them in each of the vhost file. Above is just to give you a clear cut example as how it can be working. I run a very complex Apache setup so above is just a small example to help you.

Now coming to Ajax part of your question

in chrome press Ctrl+Shift+I you will see where exactly the application is broken, it will give you some clue, (issue the request from a machine different from the machine on which you are developing web application) also if you can look at apache logs if the request from http://sample page which has ajx api actually reached your apache server that will give you more hint, if the proxy is forwarding your request correctly, post the HTTP HEADERS by using some tool in firefox like live_http in condition when there was no request and the condition when the request was made by the application that way observing the headers one can help you if the request reached the server behind the reverse proxy,also check the logs of server which is running reverse proxy if the request from web reached it or not and if the request reached what is the URL that was requested.This will give you a clue,

and for development purpose in your .conf files disable the rewrite rules for some time to test ,do it one by one.

like image 141
Registered User Avatar answered Sep 26 '22 09:09

Registered User


The problem here is that the browser is trying to protect you from getting pwned by random javascript placed on some web page. If it would let all javascript to run in the same context you would lose you Facebook sessions cookies or some other data to bad guys.

In this case the culprit could be something so simple as Chrome does not consider 'dev' to be a Fully Qualified Domain Name so it will fail the same origin test. Other reason might be that at some point you are getting stuff from app.somesite.dev and at some point you send requests to 'dev'

The servers don't care what they send and it is the browser you need to fool to believe everything is coming from the same host

  1. I would replace 'dev' in the hosts file with dev.example.com 127.0.0.1
  2. I would make sure everything coming out of the Apache proxy only refers to dev.example.com no matter from which server it comes
  3. Only use dev.example.com in your code

If all else fails you could add a HTTP header 'Access-Control-Allow-Origin: *' to allow any origin, but I would not use this except just in dev-environments.

PS. Even if you get javascript from example.com:80 that javascript can't even call example.com:443 or javascript from example.com cannot make xmlhttprequests to dev.example.com

like image 22
user2977023 Avatar answered Sep 26 '22 09:09

user2977023