How to add a response header on nginx when using proxy_pass? - nginx

I want to add a custom header for the response received from the server behind nginx.
While add_header works for nginx-processed responses, it does nothing when the proxy_pass is used.

add_header works as well with proxy_pass as without. I just today set up a configuration where I've used exactly that directive. I have to admit though that I've struggled as well setting this up without exactly recalling the reason, though.
Right now I have a working configuration and it contains the following (among others):
server {
server_name .myserver.com
location / {
proxy_pass http://mybackend;
add_header X-Upstream $upstream_addr;
}
}
Before nginx 1.7.5 add_header worked only on successful responses, in contrast to the HttpHeadersMoreModule mentioned by Sebastian Goodman in his answer.
Since nginx 1.7.5 you can use the keyword always to include custom headers even in error responses. For example:
add_header X-Upstream $upstream_addr always;
Limitation: You cannot override the server header value using add_header.

Hide response header and then add a new custom header value
Adding a header with add_header works fine with proxy pass, but if there is an existing header value in the response it will stack the values.
If you want to set or replace a header value (for example replace the Access-Control-Allow-Origin header to match your client for allowing cross origin resource sharing) then you can do as follows:
# 1. hide the Access-Control-Allow-Origin from the server response
proxy_hide_header Access-Control-Allow-Origin;
# 2. add a new custom header that allows all * origins instead
add_header Access-Control-Allow-Origin *;
So proxy_hide_header combined with add_header gives you the power to set/replace response header values.
Similar answer can be found here on ServerFault
UPDATE:
Note: proxy_set_header is for setting request headers before the request is sent further, not for setting response headers (these configuration attributes for headers can be a bit confusing).

As oliver writes:
add_header works as well with proxy_pass as without.
However, as Shane writes, as of Nginx 1.7.5, you must pass always in order to get add_header to work for error responses, like so:
add_header X-Upstream $upstream_addr always;

There is a module called HttpHeadersMoreModule that gives you more control over headers. It does not come with Nginx and requires additional installation. With it, you can do something like this:
location ... {
more_set_headers "Server: my_server";
}
That will "set the Server output header to the custom value for any status code and any content type". It will replace headers that are already set or add them if unset.

You could try this solution :
In your location block when you use proxy_pass do something like this:
location ... {
add_header yourHeaderName yourValue;
proxy_pass xxxx://xxx_my_proxy_addr_xxx;
# Now use this solution:
proxy_ignore_headers yourHeaderName // but set by proxy
# Or if above didn't work maybe this:
proxy_hide_header yourHeaderName // but set by proxy
}
I'm not sure would it be exactly what you need but try some manipulation of this method and maybe result will fit your problem.
Also you can use this combination:
proxy_hide_header headerSetByProxy;
set $sent_http_header_set_by_proxy yourValue;

Related

Clearing All Response Headers in NGINX

I understand that I can use one of the following to remove specific headers from the response in NGINX
proxy_hide_header
more_clear_headers
proxy_hide_header
more_clear_headers
However, As I mentioned, my requirement is to remove all of the response headers. Above directives will only help in removing specified headers.
Is there any way I can remove all headers before sending the response?
more_clear_headers supports wildcard *
so this works for all X-Headers: more_clear_headers 'X-*';
Never tried but I assume that also more_clear_headers '*'; works.
But you have to build from source for using headers-more-nginx-modul.

How to overwrite http Content-Disposition header in nginx.conf location block?

I have a reverse proxy server that takes file from fileserver than sends them to user. I want to change filename before sending. I wrote a rule like below
location ~ downloads/(.*) {
proxy_pass http://HOST:PORT/remote.php/dav/files/$1;
add_header Content-Disposition 'attachment; "filename=$args"';
}
But when i send request i get this error;
ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION
Adding a header with add_header works well with proxy pass, but if there is an existing header value in the response it will stack the values.
If you want to replace a header value (for example replace this Content-Disposition then you will have to do this in two steps:
# 1. hide the Content-Disposition from the server response
proxy_hide_header Content-Disposition;
# 2. add a new Content-Disposition header with your changes
add_header Content-Disposition 'attachment; "filename=$args"';
See my answer on a similar question here.

Nginx: Punching a Hole Through My Cache Not Working as Expected

I have a single page app and am trying to use the query parameter nocahce=true to bypass Nginx cache for the first response (HTML file) and ALL subsequent requests initiated by it (to get CSS, JS, etc).
According to this, I can bypass my cache using the query parameter but it is not working as expected.
Steps to reproduce the issue:
Use this minified generic configuration:
http {
...
proxy_cache_path /var/temp/ levels=1:2 keys_zone=STATIC:10m inactive=24h max_size=1g;
server {
...
location / {
# Using angularjs.org as an example
proxy_pass https://angularjs.org;
proxy_set_header Host angularjs.org;
proxy_cache STATIC;
proxy_cache_valid 200 10m;
proxy_cache_bypass $arg_nocache;
add_header X-Cache-Status $upstream_cache_status always;
}
}
}
Expected:
The response header of the requests "http://servername" and "http://servername/css/bootstrap" (or any other subsequent requests initiated by http://servername?nocache=true) to bypass the cache, i.e. contain
"X-Cache-Status: BYPASS".
Actual:
The response header of "http://servername" contains "X-Cache-Status: BYPASS" but "http://servername/css/bootstrap" does not, instead the value of "X-Cache-Status" is HIT/MISS/etc depending on the cache status.
Am I using the proxy_cache_bypass in a wrong way or do I need to do more to achieve the expected behavior?
Thanks!
I was able to solve this by using cookie_nocache.
Update the directive proxy_cache_bypass to:
proxy_cache_bypass $cookie_nocache;
If you need to bypass the cache, set a cookie named "nocache" to true (any value that isn't empty nor 0 will work). Since the browser will send the cookies to subsequent requests, this will work.
To quickly test this, open the console and add the cookie like this.
document.cookie="nocache=true"

X-Frame-Options in nginx to allow all domains

I'm using nginx as a reverse proxy for my website.
I want to be able to open my website in an iFrame from a chrome extension new tab html file.
For this, I need my nginx to set X-Frame-Options to allow all domains.
According to this answer, all domains is the default state if you don't set X-Frame-Options.
My /etc/nginx/nginx.conf doesn't have the X-Frame-Options set anywhere.
Yet when I check my website response header using Postman, it shows me X-Frame-Options = SAMEORIGIN.
How can I remove this setting and load my website in an iFrame in the chrome new-tab .html file?
Solved it by changing proxy_hide_header values in /etc/nginx/sites-available/default file like so:
proxy_hide_header X-Frame-Options;
Needed to restart nginx as well as use pm2 to restart my nodejs server (for some reason, it didn't work till I made a small change to my server and restarted it).
add_header X-Frame-Options ""; did the trick for me in nginx 1.12.
Found this header in /etc/nginx/snippets/ssl-params.conf
Just needed to comment out the line:
# add_header X-Frame-Options DENY;
I found this header option in the file /etc/nginx/templates/default.conf.
add_header X-Frame-Options "SAMEORIGIN" always;
default.conf file is mentioned in my main nginx.conf file.
maybe you can try adding this in your nginx config
add_header X-Frame-Options "" always;
it works for me

How to properly setup nginx Access-Control-Allow-Origin into response header based on the Origin header from the request?

I am looking for a nginx config setup that does setup the Access-Control-Allow-Origin to the value received in the Origin.
It seems that the * method doesn't work with Chrome and the multiple URLs doesn't work with Firefox as it is not allowed by CORS specification.
So far, the only solution is to setup the Access-Control-Allow-Origin to the value received in the origin (yes some validation could be implemented).
The question is how to do this in nginx, preferably without installing additional extensions.
set $allow_origin "https://example.com"
# instead I want to get the value from Origin request header
add_header 'Access-Control-Allow-Origin' $allow_origin;
Using if can sometimes break other config such as try_files. You can end up with unexpected 404s.
Use map instead
map $http_origin $cors_header {
default "";
"~^https?://[^/]+\.example\.com(:[0-9]+)?$" "$http_origin";
}
server {
...
location / {
add_header Access-Control-Allow-Origin $cors_header;
try_files $uri $uri/ /index.php;
}
...
}
If is evil
I'm starting to use this myself, and this is the line in my current Nginx configuration:
add_header 'Access-Control-Allow-Origin' "$http_origin";
This sets a header to allow the origin of the request as the only allowed origin. So where ever you are coming from is the only place allowed. So it shouldn't be much different than allowing "*" but it looks more specific from the browser's perspective.
Additionally you can use conditional logic in your Nginx config to specify a whitelist of hostnames to allow. Here's an example from https://gist.github.com/Ry4an/6195025
if ($http_origin ~* (whitelist\.address\.one|whitelist\.address\.two)$) {
add_header Access-Control-Allow-Origin "$http_origin";
}
I plan to try this technique in my own server to whitelist the allowed domains.
Here is a part of a file from conf.f directory where people always describes their virtual hosts of Nginx.
$http_origin compares with list of allowed_origins and then in second map block the system decides what will write to "header Access-Control-Allow-Origin" according to allowed list.
Here is a part of code.
#cat /etc/nginx/conf.d/somehost.conf
map $http_origin $origin_allowed {
default 0;
https://xxxx.yyyy.com 1;
https://zzz.yyyy.com 1;
}
map $origin_allowed $origin {
default "";
1 $http_origin;
}
server {
server_name somehost.com;
#...[skipped text]
add_header Access-Control-Allow-Origin $origin always;
#....[skipped text]
}
I test it om my servers. All works fine.
Have a nice day & be healthy,
Eugene.

Resources