how to use nginx as reverse proxy for cross domains - nginx

I need to achieve below test case using nginx:
www.example.com/api/ should redirect to ABC.com/api,
while www.example.com/api/site/login should redirect to XYZ.com/api/site/login
But in the browser, user should only see www.example.com/api.... (and not the redirected URL).
Please let me know how this can be achieved.

The usage of ABC.com is forbidden by stackoverflow rules, so in example config I use domain names ABC.example.com and XYZ.example.com:
server {
...
server_name www.example.com;
...
location /api/ {
proxy_set_header Host ABC.example.com;
proxy_pass http://ABC.example.com;
}
location /api/site/login {
proxy_set_header Host XYZ.example.com;
proxy_pass http://XYZ.example.com;
}
...
}
(replace http:// with https:// if needed)
The order of location directives is of no importance because, as the documentation states, the location with the longest matching prefix is selected.
With the proxy_set_header parameter, nginx will behave exactly in the way you need, and the user will see www.example.com/api... Otherwise, without this parameter, nginx will generate HTTP 301 redirection to ABC.example.com or XYZ.example.com.
You don't need to specify a URI in the proxy_pass parameter because, as the documentation states, if proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed.
You can specify your servers ABC.example.com and XYZ.example.com as domain names or as IP addresses. If you specify them as domain names, you need to specify the additional parameter resolver in your server config. You can use your local name server if you have one, or use something external like Google public DNS (8.8.8.8) or DNS provided for you by your ISP:
server {
...
server_name www.example.com;
resolver 8.8.8.8;
...
}

Try this:
location /api {
proxy_pass http://proxiedsite.com/api;
}
When NGINX proxies a request, it sends the request to a specified
proxied server, fetches the response, and sends it back to the client.
It is possible to proxy requests to an HTTP server (another NGINX
server or any other server) or a non-HTTP server (which can run an
application developed with a specific framework, such as PHP or
Python) using a specified protocol. Supported protocols include
FastCGI, uwsgi, SCGI, and memcached.
To pass a request to an HTTP proxied server, the proxy_pass directive
is specified inside a location.
Resource from NGINX Docs

Related

Nginx proxy_pass changes behavior when defining the target in a variable

I'm reverse proxying an AWS API Gateway stage using nginx. This is pretty straightforward:
location /api {
proxy_pass https://xxxxxxxxxx.execute-api.eu-central-1.amazonaws.com:443/production;
proxy_ssl_server_name on;
}
However, this approach will make nginx serve a stale upstream when the DNS entry for xxxxxxxxxx.execute-api.eu-central-1.amazonaws.com changes as it's resolving the entry once on startup.
Following this article: https://www.nginx.com/blog/dns-service-discovery-nginx-plus/ I am now trying to define my proxy target in a variable like this:
location /api {
set $apigateway xxxxxxxxxx.execute-api.eu-central-1.amazonaws.com/production;
proxy_pass https://$apigateway:443/;
proxy_ssl_server_name on;
}
This will make API Gateway respond with a ForbiddenException: Forbidden to requests that would pass the previous setup without using a variable. Reading this document: https://aws.amazon.com/de/premiumsupport/knowledge-center/api-gateway-troubleshoot-403-forbidden/ it tells me this could be either WAF filtering my request (when WAF is not enabled for that API) or it could be a missing host header for a private API (when the API is public).
I think I might be doing one these things wrong:
The syntax used for setting the variable is wrong
Using the variable will make nginx send different headers to API Gateway and I need to intervene manually. I did try setting a Host header already, but it did not make any difference though.
The nginx version in use is 1.17.3
You have the URI /production embedded in the variable, so the :443 is tagged on to the end of the URI rather than the host name. I'm not convinced you need the :443, being the default port for https.
Also, when variables are used in proxy_pass and a URI is specified in the directive, it is passed to the server as is, replacing the original request URI. See this document for details.
You should use rewrite...break to change the URI and remove any optional URI from the proxy_pass statement.
For example:
location /api {
set $apigateway xxxxxxxxxx.execute-api.eu-central-1.amazonaws.com;
rewrite ^/api(.*)$ /production$1 break;
proxy_pass https://$apigateway;
proxy_ssl_server_name on;
}
Also, you will need a resolver statement somewhere in your configuration.
It seems like a false positive at WAF. Did you try to disable AWS WAF https://docs.aws.amazon.com/waf/latest/developerguide/remove-protection.html ?

NGINX Reverse proxy response

I am using an NGINX server as a reverse proxy. The NGINX server accepts a request from an external client (HTTP or HTTPS doesn't matter) and passes this request to a backend server. The backend server returns "a" URL to the client that will have another URL that it should use to make subsequent API calls. I want this returned URL to have the NGIX host and port number instead of the backend service host and port number so that my backend server details are never exposed. For e.g.
1) Client request:
http://nginx_server:8080
2) Nginx receives this and passes it to the backend running with some functionality at
http://backend_server:8090
3) The backend server receives this request and passes another URL to the client http://backend_server:8090/allok.
4) The client uses this URL and makes another subsequent API calls.
What I want is that in step 4 in the response the "backend_server:port" is replaced by the nginx server and port from the initial request. For e.g
http://nginx_server:8080/allok
However, the response goes back as
http://backend_server:8090/allok
my nginx.conf
http {
server {
listen 8080; --> Client request port
server_name localhost;
location / {
proxy_pass http://localhost:8090; ---> Backend server port. The backend
service and NGINX will always be on the same
machine
proxy_redirect http://localhost:8090 http://localhost:8080; --> Not sure if this is
correct. Doesn't seem to do what I want to achieve
# proxy_set_header Host $host;
}
}
}
Thanks in advance
I was able to resolve it. I had to eliminate the proxy_redirect directive from the config.

Nginx Reverse Proxy Basic Auth Base64 Url Encode

I'm using a reverse proxy in front of a web application I do not have a hand on.
To connect my user automatically, I use Basic Auth. So I pass an argument in base 64 in the url like this http://mysiteweb/monurl?User=credentialsBase64Encoded
Unfortunately, the web application behind my url proxy encodes my query string parameter. So the authentication is not good when my proxy passes it in the header.
Here is my Nginx configuration.
server {
listen 80;
root /usr/share/nginx/www;
index index.html index.htm;
server_name mydomain.com;
location /mywebapp/ {
set $basicAuth "Basic $arg_user";
proxy_pass http://localhost:3524/;
proxy_set_header Authorization $basicAuth;
}
}
How can I fix the problem without having access to the web application behind the proxy?
Thank you in advance for your answers.

Setting up proxy_pass on nginx to make API calls to API Gateway

Problem:
I've set up a Lambda function behind API gateway which works beautifully. I have a hosted site that I want only a certain location to hit the API.
Example
https://www.example.com/ (Serves up html from hosted server)
https://www.example.com/foobar (Returns a JSON payload that is generated by Lambda and returned by AWS)
Here is my server block:
location = /foobar {
proxy_pass https://someawsuri;
proxy_redirect default;
}
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
I've tried reviewing the docs and read multiple SO posts, but I haven't been able to do what I want. Everything that I've tried has produced the error 502 Bad Gateway.
Question:
How do I configure nginx to make a request to API gateway?
Thanks.
I think you need those two lines:
proxy_set_header Host "XXXXXX.execute-api.REGION.amazonaws.com";
proxy_ssl_server_name on;
Here is the explanation about the why:
The HOST header is required as is described here
The Amazon API Gateway endpoint. This value must be one of the region-dependent endpoints listed under Regions and Endpoints. In the US East (N. Virginia) region, it is apigateway.us-east-1.amazonaws.com.
The proxy_ssl_server_name on;
Enables passing of the server name through TLS Server Name Indication extension (SNI) when establishing a connection with the proxied HTTPS server.

How to fix Sinatra redirecting https to http under nginx

I have a Sinatra app running in nginx (using thin as a back-proxy) and I'm using redirect '/<path>' statements in Sinatra. However, when I access the site under https, those redirects send me to http://localhost/<path> rather than to https://localhost/<path> as they should.
Currently, nginx passes control to thin with this command proxy_pass http://thin_cluster, where thin_cluster is
upstream thin_cluster { server unix:/tmp/thin.cct.0.sock; }
How can I fix this?
In order for Sinatra to correctly assemble the url used for redirects, it needs to be able to determine whether the request is using ssl, so that the redirect can be made using http or https as appropriate.
Obviously the actual call to thin isn't using ssl, as this is being handled by the front end web server, and the proxied request is in the clear. We therefore need a way to tell Sinatra that it should treat the request as secure, even though it isn't actually using ssl.
Ultimately the code that determines whether the request should be treated as secure is in the Rack::Request#ssl? and Rack::Request#scheme methods. The scheme methods examines the env hash to see if one of a number of entries are present. One of these is HTTP_X_FORWARDED_PROTO which corresponds to the X-Forwarded-Proto HTTP header. If this is set, then the value is used as the protocol scheme (http or https).
So if we add this HTTP header to the request when it is proxied from nginx to the back end, Sinatra will be able to correctly determine when to redirect to https. In nginx we can add headers to proxied requests with proxy_set_header, and the scheme is available in the $scheme variable.
So adding the line
proxy_set_header X-Forwarded-Proto $scheme;
to the nginx configuration after the proxy_pass line should make it work.
You can force all links to go to https in the nginx layer.
in nginx.conf:
server{
listen 80;
server_name example.com;
rewrite ^(.*) https://$server_name$1 redirect;
}
This is good to have too to assure that your requests are always https

Resources