Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NGINX Reverse Proxy and Access-Control-Allow-Origin issue

I'm configuring an NGINX Reverse Proxy.

On the browser I go to:
client url: https://www.hollywood.com

Then the web page above needs to do requests to:
server url: https://server.hollywood.com/api/auth/login

This is the configuration corresponding to: server.hollywood.com:

server {
    listen 443 ssl;
    server_name             server.hollywood.com;
    # add_header 'Access-Control-Allow-Origin' "https://www.hollywood.com" always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
    ssl_certificate         ../ssl/lets-encrypt/hollywood.com.crt;
    ssl_certificate_key     ../ssl/lets-encrypt/hollywood.com.key;
    location /
    {
        proxy_pass http://localhost:9201;
        include "../proxy_params.conf";
    }
}

Experiment 1:

With the Access-Control-Allow-Origin line commented out, when I access to:
client url: https://www.hollywood.com

I get the following error on the browser console (Chrome in my case):

POST https://server.hollywood.com/api/auth/login/local 502 (Bad Gateway)
(index):1 Failed to load https://server.hollywood.com/api/auth/login/local: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.hollywood.com' is therefore not allowed access. The response had HTTP status code 502.

Experiment 2:

If I enable the Access-Control-Allow-Origin line above, then I get on the browser terminal:

Failed to load https://server.hollywood.com/api/auth/login/local: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, https://www.hollywood.com', but only one is allowed. Origin 'https://www.hollywood.com' is therefore not allowed access.

I don't know why multiple when before that header was not present???

Experiment 3:

In the other hand, if I go directly on the browser to the:
server url: https://server.hollywood.com/api/auth/login with the Access-Control-Allow-Origin line commented out, I get the following (on the Network section):

Response Headers:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 139
Content-Security-Policy: default-src 'self'
Content-Type: text/html; charset=utf-8
Date: Sat, 09 Jun 2018 06:34:00 GMT
Server: nginx/1.13.12
X-Content-Type-Options: nosniff

Before I got: "No 'Access-Control-Allow-Origin' header is present on the requested resource." but now I see above that field is in there on the Response Headers.

Experiment 4:

If I enable again the Access-Control-Allow-Origin line above, then I get the following (on the Network section):

Response Headers:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: https://www.hollywood.com
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 139
Content-Security-Policy: default-src 'self'
Content-Type: text/html; charset=utf-8
Date: Sat, 09 Jun 2018 06:34:58 GMT
Server: nginx/1.13.12
X-Content-Type-Options: nosniff

Now I get two times the field: Access-Control-Allow-Origin.

Do you have any idea why my first 2 experiments are failing getting the errors relative to: Access-Control-Allow-Origin?

Thanks!

like image 969
davidesp Avatar asked Jun 09 '18 06:06

davidesp


People also ask

How do I fix CORS policy no Access-Control allow origin?

If the server is under your control, add the origin of the requesting site to the set of domains permitted access by adding it to the Access-Control-Allow-Origin header's value. You can also configure a site to allow any site to access it by using the * wildcard. You should only use this for public APIs.

How do I enable CORS for NGINX?

To enable the NGINX configuration for CORS, with support for preflight requests, add new NGINX rule by entering into your desire web application, selecting NGINX config on the navigation menu, and clicking the Create Config option.

Is not allowed Access-Control allow origin?

This error occurs when a script on your website/web app attempts to make a request to a resource that isn't configured to accept requests coming from code that doesn't come from the same (sub)domain, thus violating the Same-Origin policy.

Why is my proxy_Pass passing to Access Control Allow Origin?

It could be that the server behind your proxy_pass was setting the Access-Control-Allow-Origin header as well. For what it's worth for future readers with a similar problem, I found that my node.js server was passing an Access-Control-Allow-Origin: '*' header for some reason, as well as the actual header I'd set in node.js to restrict CORS.

What is the proxy_pass directive in Nginx?

The proxy_pass directive can also point to a named group of servers. In this case, requests are distributed among the servers in the group according to the specified method. By default, NGINX redefines two header fields in proxied requests, “Host” and “Connection”, and eliminates the header fields whose values are empty strings.

What is the use of reverse proxy in Nginx?

In this case NGINX uses only the buffer configured by proxy_buffer_size to store the current part of a response. A common use of a reverse proxy is to provide load balancing. Learn how to improve power, performance, and focus on your apps with rapid deployment in the free Five Reasons to Choose a Software Load Balancer ebook.

Why is only update proxy_buffer_size not working in Nginx?

Note: Only update proxy_buffer_size may not work, when you run nginx -t to test the configuration, it may report following error: In this case, you need also increase proxy_buffers . When original server response a redirect use Location header, the redirect URL missing proxy server port number.


2 Answers

It could be that the server behind your proxy_pass was setting the Access-Control-Allow-Origin header as well.

For what it's worth for future readers with a similar problem, I found that my node.js server was passing an Access-Control-Allow-Origin: '*' header for some reason, as well as the actual header I'd set in node.js to restrict CORS. When commenting out my node.js cors middleware, the Access-Control-Allow-Origin: '*' header still remained.

To resolve this, I used the nginx proxy_hide_header directive to remove the header coming from node.js and manually adding it as it should be:

# proxying the
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

# local node.js server
upstream websocket {
    server 127.0.0.1:3000;
}

server {
    server_name ...;
    # ...;

    # add the header here
    add_header Access-Control-Allow-Origin https://www.hollywood.com;

    # Websockets config
    location /socket.io/ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        # do not pass the CORS header from the response of the proxied server to the
        # client
        proxy_hide_header 'Access-Control-Allow-Origin';

        proxy_pass http://websocket;
        proxy_http_version 1.1;
    }

    location / {
        # ...
        try_files $uri /index.html;
    }
}

Googling this issue was pretty hard since most people are trying to fix CORS by making the Access-Control wide open! Here was another issue with similar problems:

https://serverfault.com/questions/751678/how-can-i-replace-access-control-allow-origin-header-in-proxy-response-with-ngin

like image 132
David S Avatar answered Nov 15 '22 03:11

David S


Try this configuration:

server {
  listen 443 ssl;
  server_name server.hollywood.com;

  ssl_certificate ../ssl/lets-encrypt/hollywood.com.crt;
  ssl_certificate_key ../ssl/lets-encrypt/hollywood.com.key;

  add_header 'Access-Control-Allow-Origin' '*';
  add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
  add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';

  location / {
    if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain; charset=utf-8';
      add_header 'Content-Length' 0;
      return 204;
    }
    if ($request_method = 'POST') {
      add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      proxy_pass http://localhost:9201;
      include "../proxy_params.conf";
    }
    if ($request_method = 'GET') {
      add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      proxy_pass http://localhost:9201;
      include "../proxy_params.conf";
    }
  }
}

Code based on https://enable-cors.org/server_nginx.html

Hope it helps.

like image 29
bordalix Avatar answered Nov 15 '22 04:11

bordalix