Find and Replace with Nginx Reverse Proxy setup - search

I have a reverse proxy setup with nginx on centos 6. I am looking to take one of my pages and display different phone numbers based on what advertisement is clicked on.
I was trying to use the http_sub_module though I don't really have a clear understanding of how to find replace with it.
Example
http://mysite.com has (111) 123-4567
I would like to have the reverse proxy do a search for above number and replace with (222) 765-321
Thanks!

It's not ideal, as really the source should be rewritten, but you can use sub_filter to rewrite the content of responses for proxied requests. With your example this would be:
location /something {
...
sub_filter '(111) 123-4567' '(222) 765-321';
sub_filter_once off;
}
The default behaviour of this is to replace once (which I have disabled in the example) and to only apply the changes to html pages (this is based on the mime type of the response). This is suitable for using in a reverse proxy as it can replace the Location header with the default options, and links when you disable the sub_filter_once option.
While this module is not available unless explicitly configured at compile time, it is my experience that any package manager installed nginx has this option enabled.
You can read more about this here.

Related

I need to remove or ignore the X-Frame-Options header. Should I use a proxy?

Premise
I need a way to remove the X-Frame-Options header from the responses from a few websites before those responses reach my browser.
I am doing this so that I can properly render my custom kiosk webpage, which has iframes that point to websites that don't want to show up in frames.
What I have tried
I have tried setting up a proxy using squid and configuring its reply_header_access option to deny X-Frame-Options headers as the server receives them, but that is for some reason not working as anticipated. I have verified that I am indeed going through the Squid proxy, and I have verified that the X-Frame-Options header persists despite my squid.conf file containing the following:
reply_header_access X-Frame-Options deny all
and having built squid (using Homebrew on my Mac) with the --enable-http-violations option.
Having chased down a lot of what might have gone wrong with this approach, I have decided that the reply_header_access option must not do exactly what I thought it does (modify headers before returning them to the client).
So, I tried using another proxy server. After reading a Stack Overflow question asking about a situation roughly similar to mine, I decided I might try using the node-http-proxy library. However, I have never used Node before, so I got lost pretty quickly and am stuck at a point where I am not sure how to implement the library for my specific purpose.
Question
Using Node seems like a potentially very easy solution, so how can I set up a proxy using Node that removes the X-Frame-Options header from responses?
Alternatively, why is Squid not removing the header even though I tried to set it up to do so?
Final alternative: Is there an easier way to reach my ultimate goal of rendering any page I want within an iframe?
I used a proxy, specifically mitmproxy with the following script:
drop_unwanted_headers.py:
import mitmproxy
def requestheaders(flow: mitmproxy.http.HTTPFlow) -> None:
for each_key in flow.request.headers:
if each_key.casefold().startswith("sec-".casefold()):
flow.request.headers.pop(each_key)
def responseheaders(flow: mitmproxy.http.HTTPFlow) -> None:
if "x-frame-options" in flow.response.headers:
flow.response.headers.pop("x-frame-options")
if "content-security-policy" in flow.response.headers:
flow.response.headers.pop("content-security-policy")
To run it, do:
mitmproxy --script drop_unwanted_headers.py
Also ensure that your proxy settings point to the computer where the proxy server is running (maybe localhost) and the correct port is used.

How to configure IIS ARR to do a ProxyPass?

Problem:
Need to proxy pass requests that ONLY matches the pattern: mywebsite.com/two-letter-country-code e.g mywebsite.com/es/ to mywebsite.vendor.com/es this second url is a Third-party vendor that will return content translated.
Work In progress:
IIS doesn't natively support ProxyPass so I installed "Application Request Routing (ARR)" to configure a forward proxy following the instructions in this article https://www.iis.net/learn/extensions/configuring-application-request-routing-arr/creating-a-forward-proxy-using-application-request-routing, in the step 14 while configuring the rewrite rule it says to add:
Rewrite URL: http://{C:1}/{R:0}
If my understand is correct in my case I will want to do something like
Rewrite URL: http://mywebsite.sl.vendor.com/{C:#}
Where {C:#} will return "es" or whatever the language the URL is going to.
My questions
1. Is my rewrite understanding correct?
2. Do I have to configure the Server Farms?
I noticed that by installing ARR, "Server Farm" is now available for configuration, but not sure if there is anything I need to do there.
1. Is my rewrite understanding correct?
No, since I wanted to match the two letter country codes the Patter should be:
^([a-z]{2}/(.*)|/[a-z]{2}$)
And the Rewrite URL under Action Properties should be:
https://mywebsite.sl.vendor.com/{R:0}
{R:0} will be the back-reference of specified pattern so an incoming request for mywebsite.com/es/ will be proxy passed as mywebsite.vendor.com/es were {R:0}=es/ as expected
2. Do I have to configure the Server Farms?
Is not require to do any special configuration in the server Farms to get the forward proxy working.
The third party service I was forwarding the request to, require to have the host header to be the server forwarding the request in this case mywebsite.com but in their end they were receiving mywebsite.vendor.com, to accomplish this you have to set the property preserveHostHeader to true, this can be found in the Configuration Editor

Maintenance page for nginx based nodejs site

I want to set up a maintenance page for my site (that visitors would see) but I also want to allow devs a way to still be able to access the site and test things (though this last bit, access for devs, is a request from a project manager... not sure it's the best way to do this as it seems like we should test on a staging server).
The site is nodejs based and runs on an nginx server via a proxy_pass.
The way I would have done this under apache is to permit a get param to be passed in that would allow a dev to circumvent being redirected to the maintenance page. Can't seem to figure out how to do this under nginx with a proxy_pass.
I was able to get everything to redirect to the maintenance page but images and css were broken and would not load. Additionally I could not implement a GET param override.
Any suggestions on how to approach this? The various tutorials around the web and comments here on SO don't seem to work and I suspect it has to do with the proxy_pass usage. Not certain.
*edit: I saw this post on SO but my attempts to implement it ended up with the visitor being redirected to "/maintenance" and getting a server error instead of my maintenance page. Also, it doesn't address overriding the redirect.
This is going be a question of how you decide to filter users. If you can filter access on IP address, cookie, or some other request aspect, then it's possible to use an if directive to redirect/rewrite all other users to the maintenance page. You mention using a GET parameter -- this condition would be an example of that (using $arg_PARAMETER as documented here):
server {
if ($arg_secret != "123456") {
rewrite ^(.*)$ /maintenance$1 break;
}
location /maintenance {
#root directive etc
}
location / {
#proxy_pass directive etc
}
}
Or you could invert the condition and configuration, and only proxy_pass for the condition being true. However, ``if` directives can be problematic (see http://wiki.nginx.org/IfIsEvil) so try before deploying.
As for the issue you've found with images and CSS not loading, you'll need to ensure that these maintenance resources always continue to be served because they were likely being affected by redirection rules as well. An example location directive could be like so:
location ~ /(.*\.css|.*\.jpg) {
root /var/www/maintenance;
}

Is there a way to use Node.js in conjunction with Apache the way PERL or PHP work?

Currently using Node.js to handle all our AJAX calls, which works brilliantly but (unfortunately) still leveraging PERL to draw in-line page content, when absolutely necessary - (for instance when Facebook or some other third party site needs to call our site and read specific Meta tags that are generated by the DB) - as well as handle file uploads and stuff of that nature.
I am trying to figure out what I'd need to do to have my web server (Apache) reach out to Node.js directly, so as to replace PERL in our mix.
Would really appreciate a pointer at some documentation that explains how to set this up or (less preferably) a response saying that at present such a configuration is not possible.
I'm rather confused by most of your question - my interpretation is that you have some URLs which you want to handle with node.js and some that you want to handle with Apache+Perl
The simplest solution is to make the 2 servers available at different URLs, e.g.
http://www.example.com:80 for the node.js
and
http://www.example.com:81 for the apache + perl
Alternatively you could use one of the servers as a proxy for the other, given a particular prefix in the path. Which way around you put the servers has a lot of implications for the performance profile of the system - but the safest solution is to use node.js at the frontend. It should be straightforward to implement this (although I'm not an expert on node.js). It's also quite possible to this the other way around - with Apache at the front using mod_rewrite (and optionally mod_proxy if you want caching):
RewriteEngine on
RewriteRule ^ajax/(.*)$ http://127.0.0.1:82/$1 [P]
(you'll need mod_proxy and a proxyPassReverse rule to clean up any redirects returned by the node.js server)
Another approach would be to run a content director in front of both the servers - although this adds additional overheads. For example using nginx:
location /perl/ {
proxy_pass http://127.0.0.1:81;
}
location /ajax/ {
proxy_pass http://127.0.0.1:82;
}
If you mean that you want all requests to be handled by node.js and some of the responses are partially made up from data accessible via Apache+perl then that's a lot more complex.
If you really love Perl like me, you may feel like this module:
npm install exec_perl
see: https://github.com/tlqtangok/exec_perl

nodejs get request header from Nginx

I'm using nginx to proxy my nodejs app. In my app, I always asking a "client_id" from header. When I'm doing the local test. Everything working correct. But when I push to server and proxy by Nginx. Then the client_id lost. I can see that when nginx do the proxy, it remove my custom header "client_id".
What I want to ask is:
is there a way to make sure nginx can pass my client_id to nodejs?
is there a way can make nginx pass whatever the custom headers?
Thanks #Peter Lyons, I just found the reason. Yes, nginx do pass all headers to the destination server as default. But, the exception is, as default, nginx block all headers which the name contain an underscore "_".
I don't know why nginx do this. But in this question, this underscore thing is the reason that I can't get my header "client_id".
There are 2 way to solve it:
1, change the header name to avoid the underscore, in this question, change "client_id" to "clientId" or "client-id"
2, in nginx.conf, inside http part, set underscores_in_headers on;, for example:
http {
....
underscores_in_headers on;
....
}
by default, nginx's HttpProxyModule has proxy_pass_request_headers enabled, and thus will pass on the client request headers to the destination server.
My first suggestions is to try renaming your header to "X-Client-Id" to utilize the extension namespace HTTP has reserved for non-standard headers such as yours and see if nginx will forward that. If not, have a look at the proxy_set_header directive.
Side note: using a custom header at all, and specifically one called "client_id" is almost a sure sign you are reinventing the wheel or don't understand industry standards for using cookies and sessions. Unless you are really sure you need this, you may want to step back and rethink your underlying problem.

Resources