nginx rewrite secure link - nginx

I am trying to rewrite a secure link, here is my nginx conf:
location /files/ {
deny all;
return 403;
}
# MEMBERS ONLY #####
location /auth/ {
secure_link $arg_h,$arg_e;
secure_link_md5 authkey$uri$arg_e;
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 403;
}
rewrite ^/auth/(.*)$ /files/$1 break;
add_header Content-Disposition "attachment; filename=$arg_f";
}
Its work if I put download link like this:
http://13.37.13.37/auth/path/to/dir/file.zip?h=sdiouqosid&e=1337&f=the_file.zip
but it does not if I print link like this:
http://subdir.mysite.org/auth/path/to/dir/file.zip?h=sdiouqosid&e=1337&f=the_file.zip
Please note:
subdir.mysite.org has "A" redir to 13.37.13.37 in DNS records
13.37.13.37 is different server than mysite.org
Also:
- http://subdir.mysite.org/path/to/something/somefile.zip works great, it's only when I use secure_link that it fails (returns either a 403 or a fail to load ressource). I guess it has something to do with my url_rewrite. I tried a lot of things without any success regarding this weird behaviour.
Thank you for your help
EDIT:
full nginx below:
user www-data;
worker_processes 2;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
#server_tokens off;
keepalive_timeout 65;
gzip on;
gzip_disable "msie6";
limit_conn_zone $binary_remote_addr zone=freeuser:10m;
map $request_uri $request_qs {
default '';
~.*\?(?P<key>.+)$ $key;
}
server {
listen 80;
server_name localhost;
root /var/www;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
access_log off;
add_header Cache-Control public;
}
location ~* \.(jpg|jpeg|gif|css|png|js|ico|swf|mp3)$ {
expires 365d;
access_log off;
}
location /file/ {
deny all;
return 403;
}
location /auth/ {
secure_link $arg_h,$arg_e;
secure_link_md5 authkey$uri$arg_e$remote_addr;
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 403;
}
rewrite ^/auth/(.*)$ /file/$1 break;
add_header Content-Disposition "attachment; filename=$arg_f";
}
}
}

I'd say change the /files block, because right now it's logical to return 403, because you just deny all.
location /files/ {
internal;
}
This would return 404 for non authorized instead of 403, don't know if that works for you.

I solved my problem editing the "Reverse" (hostname).
Regards,

Related

When using Nginx reverse proxy, how can I set IP whitelist based on request URI parameter?

My url like this:
http://myserver/app/inf?ConId=Obj%3Acom.aaa.bbb%3A3712 # Only IP in whitelist can access
http://myserver/app/...... # all user can access
When the parameter of ConId is Obj%3Acom.aaa.bbb%3A3712, I need to restrict only specific IP can access my server.
I tried the following Nginx configuration but not working.
location / {
if ( $arg_ConId = "Obj%3Acom.aaa.bbb%3A3712" ) {
allow 192.168.1.104;
deny all;
}
proxy_pass http://192.168.234.130:80;
add_header Access-Control-Allow-Origin *;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
allow all;
}
Please help, thanks!
Thanks #araisch,my final working Nginx Configuration is:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#keepalive_timeout 0;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
error_page 403 /403.html;
location = /403.html {
root html;
}
if ($arg_ConId = "Obj%3Acom.aaa.bbb%3A3712") {
set $BLOCKING A;
}
if ($remote_addr != "192.168.3.11") {
set $BLOCKING "${BLOCKING}B";
}
if ($BLOCKING = AB) {
return 403;
break;
}
location / {
proxy_pass http://192.168.234.130:80;
add_header Access-Control-Allow-Origin *;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
allow all;
}
}
}
Could use something like:
if ($arg_ConId = "Obj%3Acom.aaa.bbb%3A3712") {
set $BLOCKING A;
}
if ($remote_addr != 192.168.1.104) {
set $BLOCKING "${BLOCKING}B";
}
if ($BLOCKING = AB) {
return 403;
break;
}
in server block.
Problems in your code:
if Directives in location are considered as evil due to nginx` strange declaration rules. They're doing most of the time strange things, so try to avoid it.
$arg_ContainerOID does not catch an argument named "ConId"
Remark: This is not working in dockerized nginx in bridge mode, because the real IP is masked by the firewall.
You can use something like this:
location / {
auth_request /auth-here;
}
location /auth-here {
internal;
proxy_pass http://192.168.234.130:80/auth.php;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
Then in your script you can check $_SERVER['HTTP_X_ORIGINAL_URI'] and return HTTP 200 to allow the request or HTTP 403 to deny the request.
You will need the http_auth_request_module for the above to work, as explained in the documentation.

Nginx looking for files instead of URI when proxying

I'm trying to setup nginx as reverse proxy.
When I using just this simple config, all works well.
location / {
proxy_pass https://domain.name;
proxy_ssl_server_name on;
}
But in my case I have a legacy API and a lot of conditions, and when I using more complex prefix, regex or exact match in case, when my URI looks like this one:
/v1/Server.ashx?parameter=value
nginx looking for file Server.ashx in default root folder "/usr/share/nginx/html/v1/Server.ashx" instead of proxying, and returns 404.
How can I fix this problem?
In my case, this approach helped.
Open for any other advices.
server{
listen 8111;
server_name 192.168.137.43;
location /v1/Server.ashx {
error_page 418 = #specificpage;
error_page 419 = #websocket;
if ($query_string = "parameter=value") {
return 418;
}
if ($query_string = "") {
return 419;
}
if ($query_string = "otherparameter=othervalue") {
return 419;
}
proxy_pass https://domain.name;
proxy_ssl_server_name on;
}
location / {
error_page 419 = #websocket;
if ($request_uri = "/v2") {
return 419;
}
if ($request_uri = "/v2?parameter=value") {
return 419;
}
proxy_pass https://domain.name;
proxy_ssl_server_name on;
}
location #specificpage {
proxy_pass https://other.domain.name;
proxy_ssl_server_name on;
}
location #websocket {
proxy_pass http://domain.name;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}

Can not get headers and status code returned by auth_request

I have the following test nginx configuration:
user nginx;
worker_processes auto;
error_log /dev/stderr debug;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /dev/stderr main;
sendfile on;
keepalive_timeout 65;
upstream content {
server 127.0.0.1:4001;
}
server {
listen 4000;
server_name test;
gzip off;
autoindex off;
location /test-auth {
add_header X-Test "testvalue";
return 200;
}
location /proxy {
add_header "X-Test1" "test1";
auth_request /test-auth;
auth_request_set $test $sent_http_x_test;
auth_request_set $test2 $upstream_status;
add_header X-Test $test;
add_header X-Test2 $test2;
proxy_pass http://content?test=$test&test2=$test2;
proxy_pass_request_body off;
}
}
server {
listen 4001;
add_header X-Test3 "test3";
return 200 "testt response $args";
}
}
I expect that requesting the /proxy URL will return all test headers: X-Test (header returned by the auth request), X-Test1 (just a sample), X-Test2 (value of the auth request HTTP status), X-Test3 (set by the content downstream).
But in the reality, this request only returns X-Test1 and X-Test2. I can not get any value (headers or return status) by the auth_request_set directive. I tried both variants of variable names I found in google: $sent_http_x_test and $upstream_http_x_test but no luck. The $test variable is always empty.
I saw the following official example: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/ but the auth_request_set $test2 $upstream_status; line also doesn't work and the $test2 variable is always empty.
What I'm doing wrong?
The problem is that /test-auth location has no upstream configured, you could try the configure below.
$upstream_http_x_test is correct.
user nginx;
worker_processes auto;
error_log /dev/stderr debug;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /dev/stderr main;
sendfile on;
keepalive_timeout 65;
upstream content {
server 127.0.0.1:4001;
}
server {
listen 4000;
server_name test;
gzip off;
autoindex off;
location /real-auth {
add_header X-Test "testvalue";
return 200;
}
location /test-auth {
proxy_pass http://127.0.0.1:4000/real-auth;
}
location /proxy {
add_header "X-Test1" "test1";
auth_request /test-auth;
auth_request_set $test $upstream_http_x_test;
auth_request_set $test2 $upstream_status;
add_header X-Test $test;
add_header X-Test2 $test2;
proxy_pass http://content?test=$test&test2=$test2;
proxy_pass_request_body off;
}
}
server {
listen 4001;
add_header X-Test3 "test3";
return 200 "testt response $args";
}
}

NGINX How to rewrite a pathname but not files?

I have a NGINX server that serves a UI at /. The UI is running on localhost:8081 and the server runs on localhost:8080.
I need any pathname that is entered to be passed to the root of the UI.
For example:
localhost:8080/search should proxy_pass to localhost:8081
but files should not be changed:
localhost:8080/main.css => localhost:8081/main.css
This works but isn't dynamic
I tried to use a separate location for each pathname however I want the configuration to be dynamic for future development.
location / {
proxy_pass http://localhost:8081;
}
location /search {
proxy_pass http://localhost:8081/;
}
location /foobar {
proxy_pass http://localhost:8081/;
}
File name handler
I tried catching the file names but you can't proxy_pass within a regex location block.
location ~* \.(.*?)$ {
proxy_pass http://localhost:8081/;
}
try_files
I tried using try_files but nginx didn't serve anything (gave me a prompt to set up nginx)
location / {
try_files $uri $uri/ #app;
}
location #app {
proxy_pass http://localhost:8081;
}
My Nginx config looks like this without the location blocks
worker_processes 1;
error_log /usr/local/etc/nginx/logs/error.log notice;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '[$time_local] $remote_addr - "$request" '
'$status "$http_referer" => "$proxy_host" $uri';
log_format log_server escape=json '$request_body';
access_log /usr/local/etc/nginx/logs/access.log main;
proxy_max_temp_file_size 0;
proxy_buffering off;
sendfile on;
keepalive_timeout 65;
gzip on;
server {
listen 8080;
server_name localhost;
rewrite_log on;
add_header 'Access-Control-Allow-Origin' 'http://localhost';
add_header 'Access-Control-Allow_Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,Keep-Alive,User-Agent,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
location / {
# stuff from above + headers
}
}
}
I am using webpack dev server for local development however the final bundle has the structure:
/root
bundle.js
main.css
index.html
cd6c777f1945164224dee082abaea03a.woff2
etc...

Nginx - reverse proxy a Ghost blog with /subfolder redirect

I have a working nginx instance with the rules below. But I'm having difficulties pointing all the requests to domain.com/ghost
I tried modifying the location / {} block to location /ghost/ {} but with no success. I just get a 404 from the ghost app. Any suggestions?
server {
listen 80;
server_name domain.com;
root /home//user/ghost/;
index index.php;
# if ($http_host != "domain.com") {
# rewrite ^ http://domain.com$request_uri permanent;
# }
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:2368;
}
location ~* \.(?:ico|css|js|gif|jpe?g|png|ttf|woff)$ {
access_log off;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public, mustrevalidate, proxy-revalidate";
proxy_pass http://127.0.0.1:2368;
}
location = /robots.txt { access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }
location ~ /\.ht {
deny all;
}
}
I'm using a regexp location directive for a similar proxy setup. This is the minified configuration file:
worker_processes 1;
pid /path/to/file.pid;
worker_priority 15;
events {
worker_connections 512;
accept_mutex on;
}
http {
server {
error_log /path/to/log/error.log error;
listen 127.0.0.1:9000;
server_name example.com;
location ~* (/ghost) {
expires epoch;
proxy_no_cache 1;
proxy_pass http://localhost:1234;
}
location / {
proxy_pass http://localhost:1234;
}
}
}
Have solved similar problem with other apps which have no support for subfolders. Both apps are built on one platform, so they both tries to work in /fx dir. I had to place one of them in to subfolder /gpms .
The idea is to redirect requests with referer from subfolder to destinations which links outside of subfolder - i just add subfolder to beginning of such uris. It is not ideal, but it works.
Here is my nginx config:
server {
listen 80;
server_name mydomain.com;
location / {
rewrite ^/$ /fx/;
proxy_pass http://127.0.0.1:56943/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 300;
}
error_log /var/log/nginx/debug.log debug;
set $if_and_hack "";
if ( $http_referer ~ '^http://mydomain.com/gpms/.*$' ) {
set $if_and_hack "refgpms";
}
if ( $uri !~ '^/gpms/.*$' ) {
set $if_and_hack "${if_and_hack}_urinogpms";
}
if ( $if_and_hack = "refgpms_urinogpms" ) {
rewrite ^/(.*)$ http://$host/gpms/$1;
}
location /gpms/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cookie_path /fx /;
proxy_pass http://127.0.0.1:12788/fx/;
proxy_redirect default;
}
}
External links will be broken, but it is not critical for me and i guess it may be corrected.
$if_and_hack is for overcome nginx limitation on nested conditions.
By the way i have got a cookies issue, because they was set with path, and hit browser bug with not sending cookies for a new path after redirect, so i just remove path from cookies.
Note full link form in rewrite - this form of rewrite immediately redirects browser to new page, you should not change it to just "/gpms/$1".
As alternative, i guess, it may be possible to use nginx module to inspect html content and modify links. I have not tried this. Or consider to use subdomains instead of subfolders.
Good news! As of version 0.4.0 Ghost now supports subdirectory installation. And there are already people who've figured this out and created tutorials.

Resources