I'm having a very hard time understanding exactly when nginx overwrites my add_header directives.
I have the following:
include /etc/nginx/vhost.d/ihc.example.com;
location = /auth {
proxy_pass http://sso.example.com/auth/login;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
auth_request /auth;
auth_request_set $saved_set_cookie $upstream_http_set_cookie;
add_header Set-Cookie $saved_set_cookie; #I don't see this header in the response
proxy_pass http://ihc.example.com;
include /etc/nginx/vhost.d/ihc.example.com_location;
}
The problem I'm having is that the auth_request_set $saved_set_cookie $upstream_http_set_cookie; cookie doesn't appear in the response.
Now if I remove the include /etc/nginx/vhost.d/ihc.example.com_location; line, it will appear, but this file contains a shared CORS fix that I would really, really like to keep:
if ($cors = 'trueGET') {
add_header 'Access-Control-Allow-Origin' $http_origin; #I see this header in the response
[...]
How can I achieve both without having to repeat the CORS headers in every location? And what is causing this to become overwritten? As I read the documentation, location should overwrite server, but in this case, what is causing this new "scope"?
I finally found the root cause of my issue:
Ifs are evil
Apparently, using if statements in location blocks leads to unspecified behaviours. Unfortunately for me, this means rethinking my entire setup, and potentially switching to OpenResty instead.
Related
I would like to configure Nginx to have one route on my domain proxy to another URL. More specifically, I'd like my.domain.com/special_route to proxy to another.domain.com and for the URL to remain unchanged in the address bar. For example, I'd like my.domain.com/special_route/some_path to proxy to another.domain.com/some_path, while the URL remains unchanged.
This is the configuration I have added so far:
set $another_url https://another.domain.com;
location ~ /special_route(/?.*)$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header 'Access-Control-Allow-Origin' '*';
proxy_pass $another_url$1;
}
It appears to work mostly as intended with one notable exception. my.domain.com/special_route/some_path works, my.domain.com/special_route/ also works. However, my.domain.com/special_route (without the trailing slash) does not work. It appears to proxy to another.domain.com/special_route.
What do I need to change or add to my config to get the base route working without the trailing slash?
When the $1 is empty, it becomes just proxy_pass http://upstream which means the url is passed in full to the backend (/special_route).
The variable need to be updated to / in such cases. This is one possible method:
# tip: it should start with ^/ unless you do mean
# to allow accessing /thing/special_route in the same fashion
location ~ ^/special_route(/?.*)$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# another tip: unless you know what you're doing,
# don't use $proxy_add_x_forwarded_for. Just use $remote_addr
# otherwise people may be able to fake their ip in some cases
proxy_set_header X-Forwarded-For $remote_addr;
add_header 'Access-Control-Allow-Origin' '*';
set $proxy_url $1;
if ($proxy_url = '') {
set $proxy_url /;
}
proxy_pass $another_url$proxy_url;
}
I am configuring a odoo server to block certain routes for people outside of some networks. I am using Nginx as a reverse proxy on this server.
My issue is with the route /web/session/lougout. When i add the two following blocks to my config, browsers start caching the 303 answer from the route and stop sending headers to the server. Since the headers are missing, it prevents the server from invalidating the session and leads to a bunch of issues.
location ~ ^/web/ {
add_header Content-Security-Policy upgrade-insecure-requests;
proxy_pass http://odoo-xxx-test;
proxy_buffering on;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
expires 864000;
allow *some ip* ;
allow *some ip* ;
allow *some ip* ;
deny all;
}
location ~ ^\/web\/(action\/|content\/|static\/|image\/|login|session\/|webclient\/) {
add_header Content-Security-Policy upgrade-insecure-requests;
proxy_pass http://odoo-xxx-test;
proxy_cache_valid 200 60m;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering on;
expires 864000;
}
From my understanding, the first location should deny access to all routes outside of the 3 allowed ips and the second should allow everyone outside of those 3 ips to access those 7 routes. I dont understand how those two block affect the caching of the /web/session/logout route, removing those two directives fixes the issues but this behavior is in the requirements for the projects.
Any help would be welcome!
Found the solution to my issue, turns out the expires directive was making the NGINX server cache the 303 response and serve it without contacting the server behind the proxy.
Removing the expires directive from both location fixed our issue.
So I have set up a reverse proxy to tunnel my application.
Unfortunately the application thinks it is served via http and not https and gives out URLs with port 80.
How can I handle this in the nginx reverse proxy? (by rewriting maybe)
When I go on the page:
https://my.server.com
index.php loads, everything is okay
after clicking something I have a URL like this:
https://my.server.com:80/page/stuff/?redirect_to
which throws an error within the browser because my reverse proxy doesn't serve SSL on port 80.
How can I migitate this?
My current nginx ssl vhost for the site:
... ssl stuff ...
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
location / {
proxy_pass http://localhost:22228;
proxy_buffering off;
proxy_redirect off;
proxy_read_timeout 43800;
proxy_pass_request_headers on;
proxy_set_header Connection "Keep-Alive";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass_header Content-Type;
proxy_pass_header Content-Disposition;
proxy_pass_header Content-Length;
proxy_set_header X-Forwarded-Proto https;
}
(yes I know my request headers look like a christmas tree 🎄)
Also bonus points if you show where the documentation addressing this issue is and what the mechanism is called.
For rewriting response body you can use http_sub_module:
location / {
proxy_pass http://localhost:22228;
sub_filter_once off;
sub_filter_types text/css application/javascript; # in addition to text/html
sub_filter "//my.server.com:80/" "//my.server.com/";
}
Many people says (1, 2) that you need to disable compression when using sub_filter directive:
proxy_set_header Accept-Encoding "";
For me, it works fine without this line in config, but it can be a feature of OpenResty which I use instead of nginx.
If your app generates HTTP 30x redirects with explicit indication of domain:port, you can rewrite Location header value with the proxy_redirect directive:
proxy_redirect //my.server.com:80/ //my.server.com/;
I want to use NGINX to as a proxy to get to Deluge which is inside my home network (NGINX is publically available).
This configuration works:
location 8112;
location / {
proxy_pass http://deluge_address:8112;
}
However I'd like to use an address in form of http://nginx_address/deluge to be proxied to internal http://deluge_address:8112.
I tried the following:
location /deluge/ {
proxy_pass http://deluge_address:8112/;
}
(I tried different combinations of trailing / - none work).
But I get 404 Not found instead.
I have some knowledge about networks, but not too much.
Does anybody have any idea what I'm doing wrongly?
I did find a solution for this, but found a bug also in Nginx in the same time
https://trac.nginx.org/nginx/ticket/1370#ticket
Edit-1
Seems like bug i logged was an invalid one, which even helped me understand few more things. So I edited the config a bit.
You need to use below config
location ~* /deluge/(.*) {
sub_filter_once off;
sub_filter_types text/css;
sub_filter '"base": "/"' '"base": "/deluge/"';
sub_filter '<head>' '<head>\n<base href="/deluge/">';
sub_filter 'src="/' 'src="./';
sub_filter 'href="/' 'href="./';
sub_filter 'url("/' 'url("./';
sub_filter 'url(\'/' 'url(\'./';
set $deluge_host 192.168.33.100;
set $deluge_port 32770;
proxy_pass http://$deluge_host:$deluge_port/$1;
proxy_cookie_domain $deluge_host $host;
proxy_cookie_path / /deluge/;
proxy_redirect http://$deluge_host:$deluge_port/ /deluge/;
}
The key was to insert a base url into the pages using below
sub_filter '<head>' '<head>\n<base href="/deluge/">';
And then make replacement in src and href attributes in html. And also url(' in css entries.
Luckily deluge has a JavaScript config which has the base url. So we can override the same by adding
sub_filter '"base": "/"' '"base": "/deluge/"';
I faced the same problem, luckily I found a better and official solution:
Reverse Proxy with Deluge WebUI
proxy_set_header X-Deluge-Base "/deluge/";
add_header X-Frame-Options SAMEORIGIN;
My final settings:
location /deluge {
proxy_pass http://127.0.0.1:8112/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 75;
proxy_send_timeout 3650;
proxy_read_timeout 3650;
proxy_buffers 64 512k;
client_body_buffer_size 512k;
client_max_body_size 0;
# https://dev.deluge-torrent.org/wiki/UserGuide/WebUI/ReverseProxy
proxy_set_header X-Deluge-Base "/deluge/";
add_header X-Frame-Options SAMEORIGIN;
}
Has anyone run into the problem of mod-security only allowing one set-cookie through a proxy request response? We are using nginx with mod-security and seeing all but the last set-cookie be removed by nginx on the response from our application server. We are applying the mod-security in the location section
location ~* ^/(test|securitytest|$) {
ModSecurityEnabled on;
ModSecurityConfig modsecurity.conf;
create_full_put_path on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://app;
proxy_read_timeout 10;
proxy_redirect off;
}
there was a bug in modsecurity+nginx that was dropping all except one cookie for each request. It was fixed, have a look at:
https://github.com/SpiderLabs/ModSecurity/issues/154