Xalio08
Xalio08

Reputation: 1024

Nginx CORS with Angular

So I have been pulling my hair out for a couple of days now. I have a backend server, using Nginx, Gunicorn and Django. I use it as a REST server, with Django Rest Framework, and using token authentication with Django Rest Auth. The address of this server is api.dev.mysite.com

This server is called from a frontend interface using AngularJS, also handled by Nginx, with the address dev.mysite.com

Everything is running locally, and as you can see the two domains are different. Whenever I try to make a request from the fronted to the backend, I get the following error:

Failed to load resource: Origin https://dev.mysite.com is not allowed by Access-Control-Allow-Origin.

I know what you think: Easy, just add add_header 'Access-Control-Allow-Origin' 'http://dev.mysite.com'; to your nginx.conf file on the backend, and everything will work, like here. or here.

But it doesn't. I tried everything, moving it to different locations, putting a '*' instead of the address, enabling and disabling SSL... The only thing that works is when I manually disable Cross-Origin restrictions in the browser. And the best part is that when I do disable those restrictions, I can see the Access-Control-Allow-Origin header set to http://dev.mysite.com in the debug console of my browser!

Any idea of what might be going wrong?

Here is my nginx.conf file:

worker_processes 1;

user me staff;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024; # increase if you have lots of clients
  accept_mutex off; # set to 'on' if nginx worker_processes > 1
}

http {
  include mime.types;
  default_type application/octet-stream;
  access_log /tmp/nginx.access.log;
  sendfile on;

  upstream app_server {
    # for UNIX domain socket setups
     server unix:/tmp/gunicorn.sock fail_timeout=0;
  }

  # Common SSL Settings
  ssl_session_cache shared:SSL:10m;
  ssl_session_timeout 10m;

  ssl_prefer_server_ciphers on;
  ssl_ciphers ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:!RC4:+HIGH:+MEDIUM:!kEDH;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  server {
    # if no Host match, close the connection to prevent host spoofing
     listen 80 default_server;
     return 444;
  }

  server {
     listen 443 ssl;
     server_name api.dev.mysite.com;

     # Self-signed certificate.
     ssl_certificate ssl/nginx-selfsigned.crt;
     ssl_certificate_key ssl/nginx-selfsigned.key;

     access_log /tmp/api.dev.intelligence.access.log;
     error_log /tmp/api.dev.intelligence.error.log;

     location / {
        add_header 'Access-Control-Allow-Origin' 'https://dev.mysite.com';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding';

        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;
        }

        proxy_pass http://127.0.0.1:9000;
        proxy_set_header    Host            $host;
        proxy_set_header    X-Real-IP       $remote_addr;
        proxy_set_header    X-Forwarded-for $remote_addr;
        proxy_set_header    X-Forwarded-Protocol $scheme;
      }
  }

  server {
    client_max_body_size 4G;

    # Self-signed certificate.
    ssl_certificate ssl/nginx-selfsigned-front.crt;
    ssl_certificate_key ssl/nginx-selfsigned-front.key;

    # Listen on 80 and 443
    listen 80;
    listen 443 ssl;
    listen [::]:443 ssl;

    # set the correct host(s) for your site
    server_name dev.mysite.com;

    # Redirect all non-SSL traffic to SSL.
    if ($ssl_protocol = "") {
      rewrite ^ https://$host$request_uri? permanent;
    }

    keepalive_timeout 5;

    access_log /tmp/dev.intelligence.access.log;
    error_log /tmp/dev.intelligence.error.log;

    location / {
        root /path/to/app/current/;
        index index.html index.htm;   
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /path/to/app/current/public;
    }
  }
}

Upvotes: 2

Views: 7135

Answers (1)

Xalio08
Xalio08

Reputation: 1024

Alright so I found the solution to my problem. I did three things:

  1. Deleting all 'add_header' lines from my nginx.conf file. It now looks like that:

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header    Host            $host;
        proxy_set_header    X-Real-IP       $remote_addr;
        proxy_set_header    X-Forwarded-for $remote_addr;
        proxy_set_header    X-Forwarded-Protocol $scheme;
    }
    
  2. Installing Django Cors header, and adding the following lines to my settings.py:

    CORS_ORIGIN_ALLOW_ALL = False
    CORS_ALLOW_CREDENTIALS = True
    CORS_ORIGIN_WHITELIST = (
        'dev.myapp.com'
    )
    
  3. Added the following lines to my .config file in Angular:

    $httpProvider.defaults.useXDomain = true;
    $httpProvider.defaults.withCredentials = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
    

    I tried all of those things separately, but I guess all three were needed.

Upvotes: 4

Related Questions