I have two locations in nginx, where one redirect to another. I want to make next:
First one allow direct access in browser and redirect query to second location. Second location transform get to post, make proxy query and allowed only from first location.
First:
location /first/ {
rewrite ^ /second/ permanent;
}
Second:
location /second/ {
proxy_method POST;
proxy_set_body '{ "arg1": "$arg_arg1", "arg2": "$arg_arg2" }
proxy_pass https://some_api.com/
}
How could I check in second location if it redirected from first one (not direct access in browser) and show some 40x error if it was direct access?
Trying to use internal directive, but this rewrite does not fall into the category of internal redirects.
Redirect using to hide /first/ url in user browser
Thanx in advance
This is not about nginx, rather about HTTP protocol and user browser behavior. Whatever you are trying to do, I think you are trying to do it in a wrong way. Generally, you need to generate some one-time token at your first location and use it at the second one, but this is a web app job, nginx is just a web server and not a web framework (however it can be possible using third party modules like lua-nginx-module). If you want to do it using nginx itself, no matter what solution you'll finished up with, it will be possible to trace and spoof it.
Here is an idea in general:
location /first/ {
# set cookie with an access token
add_header Set-Cookie "my_token=my_super_password; path=/second/" always;
# do not use 301 redirect here or it will be cached by user browser, use 302 only!
rewrite ^ /second/ redirect;
}
location /second/ {
if ($cookie_my_token != "my_super_password") { return 403; }
# clear the token cookie on response
add_header Set-Cookie "my_token=deleted; path=/second/; expires=Thu, 01 Jan 1970 00:00:00 GMT" always;
... rest of configuration here
}
Related
Currently I have a service setup at https://example.com that, as part of its standard logging setup, logs the request origin. This is a public data API, it's open to any and every origin.
This service used to be at https://example_2.com, but I proxy that address to the new to ensure non-breaking service for everyone else. This is done in the following way:
server {
...
server_name example_2.com;
location / {
proxy_pass https://example.com;
add_header Access-Control-Allow-Origin *;
}
}
The problem is that the Origin header turns up as null at the proxy destination. I need the header to arrive intact so I can know where the request came from.
I tried adding proxy_pass_request_headers but that seemingly does nothing at all.
While I haven't fixed passing Origin through, I did learn that Nginx automatically populates Referer which will work for my purpose. It's not great, and I'd love to know how to get a non-null Origin, but I thought I'd post this as it might help others who similarly can get away with this as a "solution".
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.
I am now enabling language support for my web site. I am including the language as part of the URL. For example: domain.com/en/page I need to setup 301 redirects for existing search engine indexing.
The following works in Nginx to redirect from domain.com/blog to domain.com/en/blog
location = /blog {
return 301 /en/blog;
}
I don't understand the redirect needed to go from domain.com/blog/read/# to domain.com/en/blog/read/# (where # is the sequence field in a postgres database table)
I have spent time looking, searching and reading docs to find this answer myself. I am not understanding.
To prefix the existing requested URI with /en you can use:
return 301 /en$request_uri;
The above will add the three characters before the existing request and also include any arguments that may be present.
To match any URI that begins with /blog, use location /blog { ... }. To match any URI that begins with /blog/read/ use location /blog/read/ { ... }.
Nginx chooses a location to process a request based on a set of rules. So, you will need to consider the other location blocks present within your configuration.
I have 2 locations in nginx.conf i want to give access with .ts extention only if you have accessed through .m3u8 otherwise it will return 403.
So basically http://xxx/hello.m3u8 Will grant you access to play the .ts list inside.
But trying to access the chunks alone like in http://xxx/hello-123.ts wouldn't work.
Making the access to cache in period time would also be fine.
This is the code i have come to so far, help would be appreciated.
location ~ \.m3u8 {
root /mnt/hls;
add_header Cache-Control no-cache;
set $access 1;
}
location ~ \.ts {
if ($access = "") {
return 403;
}
root /mnt/hls;
add_header Cache-Control no-cache;
}
You can't block the access to the .ts segments if you want to be able to play them back. If you're looking for some form of DRM you could use token-based authentication coupled with segment encryption with a rotating key served over HTTPS. This will make it harder but not impossible to record your content.
Implementing an authentication module in Nginx is pretty easy. See the tutorial and example project here: Nginx Auth Token Module.
Right now, I am migrating the domain of my app from app.example.com to app.newexample.com using the following nginx config:
server {
server_name app.example.com;
location /app/ {
rewrite ^/app/(.*)$ http://app.newexample.com/$1;
}
}
I need to show-up a popup-banner to notify the user of the domain name migration.
And I want to this based upon the referrer or some-kind-of-other-header at app.newexample.com
But how can I attach an extra header on the above rewrite so that the javascript would detect that header and show the banner only when that header is present coz the user going directly at app.newexample.com should not see that popup-banner?
The thing is that, when you "rewrite" into URI having protocol and hostname (that is http://app.newexample.com/ in your case), Nginx issues fair HTTP redirect (I guess the code will be 301 aka "permanent redirect"). This leaves you only two mechanisms to transfer any information to the handler of new URL:
cookie
URL itself
Since you are redirecting users to the new domain, cookie is no-go. But even in the case of a common domain I would choose URL to transfer this kind of information, like
server_name app.example.com;
location /app/ {
rewrite ^/app/(.*)$ http://app.newexample.com/$1?from_old=yes;
}
This gives you the freedom to process at either Nginx or in a browser (using JavaScript). You may even do what you wanted intially, issuing a special HTTP header for JavaScript in new app server Nginx configuration:
server_name app.newexample.com;
location /app {
if ($arg_from_old) {
add_header X-From-Old-Site yes;
}
}
A similar problem was discussed here. You can try to use a third-party module HttpHeadersMore (I didn't try it myself). But even if it does not work at all, with the help of this module you can do absolutely everything. Example is here.
Your redirect is missing one thing, the redirect type/code, you should add permanent at the end of your rewrite line, I'm not sure what's the default redirect code if not explicitly mentioned.
rewrite ^/app/(.*)$ http://app.newexample.com/$1 permanent;
An even better way is using return
location /app {
return 301 $scheme://app.newexample.com$request_uri;
}
Adding a get parameter as mentioned above would also be a reliable way to do it, you can easily set a session ( flash ) and redirect again to the page it self but after removing the appended get parameter.
EDIT:
Redirecting doesn't send referrer header, if the old domain is still working you could put a simple php file that does the redirect with a header call.
header("Location: http://app.newexample.com")
One possible solution without any headers would be to check the document.referrer property:
if (document.referrer.indexOf("http://app.example.com") === 0) {
alert("We moved!");
}
Using a 301 will set the referrer to the old page. If the referrer doesn't start with the old page url, it was not directed by that page. Maybe a bit quick n dirty, but should work.