nginx reverse proxy all request when location match - nginx

I am trying to use nginx to host 2 different web apps and make it work on the same domain (eg, www.myapp.com). I want to be able to detect a specific location and then load all resources from a specific app based on a location. Previously I had worked on proxying /api to a specific upstream, but the requirements are a little more complicated due to presence of other resources that needs to get loaded.
server {
listen 80;
location / {
proxy_pass http://app1;
}
location /app2/ {
proxy_pass http://app2;
}
}
upstream app1 {
server 127.0.0.1:8080;
}
upstream app2 {
server 127.0.0.1:3000;
}
When the url hits myapp.com/app2, it loads the html from app2 but there are other resources (like js, css, translations, analytics) files that are being searched in app1 (which obviously results in 404 NOT FOUND). Adding a location rule to match all css, js, etc does not make sense because both the app has their own cs, jss and other resource files. Adding a rule for hardcoded resources is also taxing beccause the it changes with every build.
The 2 main requirements are:
Load all resources from app2 when the url is www.myapp.com/app2, including all js, css and other resources. For instance, the js and css files are served at /static/js/*.js and /static/css/*.css, and they are being searched in https://app1/static/js/*.js, rather than app2. There could be additional resources in the future too so I want to remain flexible.
I don't want to rewrite the url and retain the same www.myapp.com. The url for the end-users should always remain at www.myapp.com/*, rather than using any subdomains. When using subdomains, it works as expected.

Related

Nginx proxy_pass to change root domain only behind ALB

I need to make a domain migration for an app hosted on ElasticBeanstalk behind ALB. This app uses various subdomains so I need to keep the subdomain and the request and change only the domain... I tried to setup a Nginx proxy_pass directive but I might have made mistakes as it does not work:
Practically what I want to achieve is a proxy for every type of request (post, get, put, delete...) that would redirect requests like anySubdomain.potato.net/anything/else to anySubdomain.carrot.io/anything/else
On the DNS side both wildcard subdomains *.potato.net and *.carrot.io are pointing to the same ElasticBeanstalk environment. So far I added this instruction into my Nginx configuration files, but it does not work as the potato.net domain is not redirected and lands directly on the hosted app without beeing proxied:
location ~ ^/(?<subdomain>\.potato\.net)/(?<path>.*)?$ {
# this is the desired directive at the end:
# proxy_pass https://$subdomain.carrot.io/$path;
# for test purposes I add the debug path below to output
# some info and make sure it was proxied:
proxy_pass https://$subdomain.carrot.io/proxydebug/$path;
}
Is there something wrong in that directive?

How can I route traffic to another domain without changing the browser URL?

I want to route the traffic from a domain to another domain(with different subpath) without change the URL in brower using Nginx.
For example, I /app/example/ ---> https://another_domain.com:443/dev/app/
I have tried using
location /app/example/ {
proxy_pass https://another_domain.com:443/dev/app/;
proxy_ssl_server_name on;
}
But the URL in the browser will be changed to "https://another_domain.com:443/dev/app/" when I try to access "/app/example", that it not what I want.
I have also tried using the same subpath:
location /app/example/ {
proxy_pass https://another_domain.com:443;
proxy_ssl_server_name on;
}
The URL in the browser does not change, but my requirement is to route traffic to another subpath in another domain.
Could anybody help me? How can I route the traffic to another subpath of another domain using Nginx without changing the URL in browser?
To get this working correctly, you'll need to own and control the responses of the destination server to ensure the HTML sub-resources (images, CSS, JS) work correctly. As Brad said, it's difficult to proxy third-party sites you don't control. Typically, the relative href and src tags in the destination HTML response need to use absolute URLs of the destination server URL.
When done correctly using absolute URLs, this works:
##
## ✅ https://example.com/proxy-absolute
## ❌ https://example.com/proxy-relative
##
location ~ ^/proxy-(absolute|relative)$ {
proxy_pass https://batman.dev/static/70408096/$1.html;
}
From these third-party examples, you can see how Google search is missing sub-resources. Bing detects the proxy outright and redirects to its own domain.
##
## https://example.com/google-search/apple
##
location ~ ^/google-search/([^/]+) {
proxy_pass https://www.google.com/search?q=$1;
}
##
## https://example.com/bing-search/apple
##
location ~ ^/bing-search/([^/]+) {
proxy_pass https://bing.com/search?q=$1;
}
You can't.
Proxying isn't a good solution, as you'll likely break some resources on the page by serving them from a different domain.
The best you can do is create a page that has nothing but an iframe, which loads the other site. And, this only works if the target site doesn't have frame busting.

How to proxy between 2 apps containing shared paths in a DRY way

I'm a newbie with Ngnix and I am looking for some advice to avoid repeating location blocks and preserve functionality.
I used to have one react application react.mydomain.cc
On my Nginx configuration file I was proxing everything from / to react.mydomain.cc
location / {
try_files $uri #approute;
}
location #approute {
proxy_ssl_server_name on;
set $react "http://react.mydomain.cc";
proxy_pass $react$request_uri;
}
Now, I want to replace part of the old application with a new one without having to make changes to the old.
The logic would be.
If the users goes to www.mydomain.cc he should be proxied to the new app http://new-react.mydomain.cc
The same other paths like:
/about
/contact
/blog
/whoiam
/photos
and a few more
These pages are also active through the other subdomain http://react.mydomain.cc/about but not accessible through nginx domain, www.mydomain.cc
If the user goes to
/notes
/playground
/app/*
/internal/*
he should be proxied to the old app.
Example: the user goes to www.mydomain.cc/notes and he is proxied to http://react.mydomain.cc/notes. Then he click on the link /about and he is proxied to the new app http://new-react.mydomain.cc/about even when the old app has /about.
Can anyone help me to avoid having to repeat 20 times location blocks? I'm trying to achieve the same but in a cleaner way.
Please, let me know if edition is needed to clarify. Remember I am new.

How to set exceptions for NGINX load balancer

Is it possible to configure NGINX loadbalancer in least_conn mode to make exception for certain paths?
I want to configure loadbalancer in such way that all requests required for single login operation are sent to the same backend application instance.
I have frontend app accessing duplicated backend app via nginx load balancer. All apps are deployed on Tomcat 8.5 and backend instances have configured session replication between Tomcats.
My problem is that when user is authenticated using OAuth-2.0 authorization_code grant method, frontend app gets authorization code but due to conneting to backend through load balancer it tries to obtain token using this code from another machine resulting in InvalidGrantException.
Using ip_hash mode or it's variations isn't solution for this problem as it is unstable when application is accessed through VPN.
Yes you can achieve what you want by declaring two locations and treat them differently. See example below and check this question where it explains how the priority works.
http {
upstream myapp1 {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://myapp1;
}
location /my-special-path/ {
proxy_pass http://srv1.example.com;
}
}
}
Above is a solution mainly based in your first statement that you want routing based on certain paths. If your problem is more complicated i.e these paths are dynamically created etc you can share an example to be easier to understand your specific situation.
UPDATE
Based on comment. I would really suggest to go troubleshoot your backend in order to be synced. That being said if you really want a solution for the exact problem from your nginx I would do the following:
On every response I would add a specific header which specific backend answered this request. add_header X-Upstream $upstream_addr;
On this specific path I would serve the request based on the value of that header. proxy_pass http://$http_x_upstream;
So the config would look like this:
http {
...
server {
...
location / {
add_header X-Upstream $upstream_addr always;
proxy_pass http://myapp1;
}
location /authorize/ {
add_header X-Upstream $upstream_addr always;
proxy_pass http://$http_x_upstream;
}
}
}
NOTE: Security. If you go down this path be careful that you are routing your requests based on a value that your client can manipulate. So be sure that you are at least validating this value. Check this answer for validating headers with nginx.

Nginx redirect to url with /#/url

I'm new to using nginx and I'm trying to redirect one url to another.
https://server.com/#/page.html -> https://server.com/page.html
The /#/ comes from using Angular2's router functionality. I decided to change the page to static html because Angular2 loads the entire app at start up and it's unnecessary for this single page of information to be presented as such.
My attempts at solving the problem is as follows. I can redirect from /anotherpage -> /page.html but /#/anotherpage -> /page.html loads the Angular2 app and tries to route to the non existent route.
Using this config and location directives:
server {
listen 8001;
server_name server.com;
...
#SSL Things
...
root /to/root/folder/public;
#Redirects:
location = /anotherpage {
rewrite ^/.* https://$server_name/page.html;
}
#Does not redirect:
location = /#/anotherpage {
rewrite ^/.* https://$server_name/page.html;
}
}
Any suggestions on best practices are welcome as well.
The browser does not send any information after a # is encountered.
Thus when sending https://server.com/#/page.html only https://server.com/ is seen by nginx.
Thus redirecting is not possible and changing the client side application is the only option.

Resources