set in location and if in another location - nginx

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.

Related

disallow direct access to nginx location

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
}

Nginx: How do I pass Origin header through proxy?

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".

Nginx Config, Deny Image Stored in Specific Folder If $http_cookie Isn't Set

I am currently launching a WordPress site that moves image uploads into a certain folder when they are added. On my development server I have made it so that images stored in this folder are NOT ACCESSIBLE, unless a specific $http_cookie is set in the browser. Here is the location block I'm using for this in my development NGINX config:
location ~ ^/wp-content/uploads/employee_message/(.*) {
if ($http_cookie !~ 'wp_2651267=user_employee123') {
return 301 https://sitename.com;
}
}
On the development server, when I view a file such as http://sitename.com/wp-content/uploads/employee_message/1234-5678-1234-5678/image_here.png for example, it will only allow me to view that if the I have the wp_2651267=user_employee123 cookie set. This is good.
However, when I move this location block into my production config (I'm using RunCloud) it allows the image to be viewed with or without the cookie. This is no good.
I'm seeing that this location block below is part of the default config, and my block above gets pulled in AFTER this one:
location ~ .(ico|css|gif|jpe?g|png|gz|zip|flv|rar|wmv|avi|css|js|swf|png|htc|mpeg|mpg|txt|otf|ttf|eot|woff|woff2|svg|webp)$ {
expires 1M;
include /etc/nginx-rc/conf.d/sitename.d/headers.conf;
add_header Cache-Control "public";
include /etc/nginx-rc/extra.d/sitename.location.static.*.conf;
try_files $uri $uri/ /index.php$is_args$args;
}
Is it possible that this is undoing the cookie business I'm adding in?
Here is an example config that RunCloud uses: RunCloud NGINX Config
My location block gets pulled in on this line:
include /etc/nginx-rc/extra.d/runcloud-blog.location.main.*.conf;
There are no errors when I run a test, and it has definitely been reloaded many, many times. Are there any reasons that my location block isn't working in this setup? Is there more information I can provide to help troubleshoot this?
Thanks so much for taking the time to read this! Please let me know if you have any insights.
Thanks,
-Ryan
To help people that find this question in future
Nginx then tries to match against the regular expression locations sequentially. The first regular expression location that matches the request URI is immediately selected to serve the request.
via Understanding Nginx Server and Location Block Selection Algorithms
Per the question, the less restrictive regex location was declared BEFORE the more restrictive location so it was selected as the location to serve the request.
By moving the more restrictive location BEFORE the other will cause it to be selected when the regex matches.

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.

How to create a dynamic root in Nginx based on a route value?

What I'm trying to accomplish is to be able to pass in a route such as this:
mysite.com/abc123/file.mp3
In Nginx I want it to read the abc123 and then call a piece of code (don't care what language: php, python, golang, fortran...) and then return the actual key that is needed to load the file.
In my config I have this:
server{
#lots of basic stuff here
location / {
mp4;
mp4_buffer_size 1m;
mp4_max_buffer_size 5m;
root /my_path/;
}
}
This works when I pass in my abc123/file.mp3. It will find the file and play it if that file exists in /my_path/abc123/file.mp3.
What I want is to translate (from a database) abc123 to myKey123 which would live at /my_path/myKey123/file.mp3
So, first, is this even possible?
If so, I'm not sure how to approach this. I know this question could have multiple solutions, but any direction will be appreciated.
The PHP script can issue a redirection using the X-Accel-Redirect header. This is treated by nginx as an internal redirect, so the rewritten URI is not exposed to the user. The documentation is a bit thin on details, hopefully you can find an example using PHP.
If you can ring-fence the rewritten URIs with a unique prefix, e.g. /download/myKey123/file.mp3, you can protect the files from direct access by using the internal directive. See this document for details. In which case, you will not need to obfuscate myKey123.
location /download/ {
internal;
...
}

Resources