How to enable CORS in Nginx proxy server? - node.js

As my title, here is the config file located in conf.d/api-server.conf
server {
listen 80;
server_name api.localhost;
location / {
add_header 'Access-Control-Allow-Origin' 'http://api.localhost';
add_header 'Access-Control-Allow_Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
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_redirect off;
proxy_set_header host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-forward-for $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:3000;
}
}
The nginx.conf file stay the same as default.
After I send request to api.localhost (api.localhost/admin/login), I still receive 405 error:
XMLHttpRequest cannot load http://api.localhost/admin/login. Response
to preflight request doesn't pass access control check: No 'Access-
Control-Allow-Origin' header is present on the requested resource.
Origin 'http://admin.localhost:3000' is therefore not allowed access.
The response had HTTP status code 405.

The issue is that your if condition is not going to send the headers in the parent in /. If you check the preflight response headers it would be
HTTP/1.1 204 No Content
Server: nginx/1.13.3
Date: Fri, 01 Sep 2017 05:24:04 GMT
Connection: keep-alive
Access-Control-Max-Age: 1728000
Content-Type: text/plain charset=UTF-8
Content-Length: 0
And that doesn't give anything. So two possible fixes for you. Copy the add_header inside if block also
server {
listen 80;
server_name api.localhost;
location / {
add_header 'Access-Control-Allow-Origin' 'http://api.localhost';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'http://api.localhost';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_redirect off;
proxy_set_header host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-forward-for $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:3000;
}
}
Or you can move it outside the location block, so every request has the response
server {
listen 80;
server_name api.localhost;
add_header 'Access-Control-Allow-Origin' 'http://api.localhost';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
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;
}
proxy_redirect off;
proxy_set_header host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-forward-for $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:3000;
}
}
If you only want to allow certain locations in your config for CORS. like /api then you should create a template conf with your headers
add_header 'Access-Control-Allow-Origin' 'http://api.localhost';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
and then use
include conf.d/corsheaders.conf;
in your OPTIONS block and /api block. So CORS are only allowed for the /api. If you don't care which location for CORS then you can use the second approach of moving core headers to server block

Related

Nodejs reverse proxy for static files not working with nginx

I'm trying to setup Angular + Nodejs behind Ngnix on Ubuntu.
Everything is working fine for Angular and Nodejs API but I'm not able to serve static files.
Here is my configuration (/etc/nginx/sites-enabled/default):
location / {
# First attempt to serve request as file, then as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://localhost:7777;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# preflight requests
if ( $request_method = OPTIONS ) {
add_header "Access-Control-Allow-Origin" *;
add_header "Access-Control-Allow-Credentials" true;
add_header "Access-Control-Allow-Methods" "GET, POST, PUT, HEAD, DELETE, OPTIONS";
add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept";
return 200;
}
}
location /static {
proxy_pass http://localhost:7777;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
The /api route works fine but /static doesn't.
On local, /static works fine because there is no nginx.
I have following directory structure to serve static files:
public
static
images
css
fonts
https://somewebsite.com/api/read (works fine)
https://localhost:3000/static/images/test.png (works fine)
https://somewebsite.com/static/images/test.png
is not working. What am I doing wrong?
https://localhost:3000/static/images/test.png (works fine) and https://somewebsite.com/static/images/test.png is as expected. According to your configuration, you are also redirecting /static to port 7777: proxy_pass http://localhost:7777;
Changing:
proxy_pass http://localhost:7777;
to:
proxy_pass http://localhost:3000;
should do the trick
I fixed this with following entry:
location /static/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_pass "http://localhost:7777/static/";
# preflight requests
if ( $request_method = OPTIONS ) {
add_header "Access-Control-Allow-Origin" *;
add_header "Access-Control-Allow-Credentials" true;
add_header "Access-Control-Allow-Methods" "GET, POST, PUT, HEAD, DELETE, OPTIONS";
add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept";
return 200;
}
}

i can't enable CORS in nginx

I can't Enable CORS on my API Gateway instance, this is how it looks:
Everything is installed on an nginx server under ubuntu 20.04.
React Font-end: https://example.com
-nginx
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /home/ubuntu/front;
index index.html index.htm;
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
expires -1;
# access_log logs/static.log; # I don't usually include a static log
}
location ~* \.(?:css|js)$ {
try_files $uri =404;
expires 1y;
access_log off;
add_header Cache-Control "public";
}
# Any route containing a file extension (e.g. /devicesfile.js)
location ~ ^.+\..+$ {
try_files $uri =404;
}
# Any route that doesn't have a file extension (e.g. /devices)
location / {
try_files $uri $uri/ /index.html;
}
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl; # managed by Certbot
listen [::]:443 ssl;
ssl_certificate /etc/letsencrypt/live/xxx.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/xxx.com/privkey.pem; # managed by Certbot
server_name example.com www.example.com;
root /home/ubuntu/front;
index index.html index.htm;
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
expires -1;
# access_log logs/static.log; # I don't usually include a static log
}
location ~* \.(?:css|js)$ {
try_files $uri =404;
expires 1y;
access_log off;
add_header Cache-Control "public";
}
# Any route containing a file extension (e.g. /devicesfile.js)
location ~ ^.+\..+$ {
try_files $uri =404;
}
# Any route that doesn't have a file extension (e.g. /devices)
location / {
try_files $uri $uri/ /index.html;
}
}
express Back-end: https://api.mydomain.com
code add to js
app.use(cors());
´
- nginx
upstream api {
server xx.xx.xx.xx;
}
server {
server_name api.mydomain.com;
location / {
proxy_pass http://127.0.0.1:4001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 30;
proxy_send_timeout 30;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/xx.xxxx.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/livexx.xxxx.com/privkey.pem; # managed by Certbot
}
minio objectstorage: https://minio.example.com
server {
listen 443 ssl;
server_name minio.example.com;
ssl_certificate /etc/minio/certs/public.crt;
ssl_certificate_key /etc/minio/certs/private.key;
# To allow special characters in headers
ignore_invalid_headers off;
# Allow any size file to be uploaded.
# Set to a value such as 1000m; to restrict file size to a specific value
client_max_body_size 1000m;
# To disable buffering
proxy_buffering off;
location / {
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_set_header Host $http_host;
proxy_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
proxy_pass https://localhost:9000;
# Ajouter les headers de contrôle d'accès CORS
#add_header 'Access-Control-Allow-Origin' '*' always;
#add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
#add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept' always;
#add_header 'Access-Control-Allow-Credentials' 'true' always;
}
i can manage to make http requests from example.com to api.example.com without having cors errors
but when i do an http request fomr example.com to api.example.com then from api.example.com to mini.example.com(or any api), i have cors error " Access to xmlhttprequest at https://api.example.com/upload from https://example.com has been blocked by cors policy: no 'access-control-allow-origin' header is present on the requested ressource
proxy_set_header Access-Control-Allow-Origin "*";
sovled the issue

Error: Request failed with status code 405 , payload return HTML not JSON like intended

I'm setting up a webapps using Node JS + React + NGINX on AWS
and then when i want to access the url /auth
it return me some HTML code instead of JSON like i wanted to be
i tested the code on LOCALHOST and it works fine
I tried to set the folder permission, because i think maybe user permission is the problem
I also tried editing some stuff on the Nginx.conf
below is my app.conf for the nginx
upstream webapp{
server 127.0.0.1:3018;
}
server_names_hash_bucket_size 64;
server_names_hash_max_size 512;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name 127.0.0.1;
server_name_in_redirect off;
if ($http_x_forwarded_proto = 'http'){
return 301 https://$host$request_uri;
}
location / {
root /home/website/client/build;
try_files $uri /index.html;
log_not_found off;
access_log off;
}
#error_page 405 =200 $uri;
if ( $http_user_agent ~* (nmap|nikto|wikto|sf|sqlmap|bsqlbf|w3af|acunetix|havij|appscan) ) {
return 403;
}
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block;";
add_header Strict-Transport-Security "max-age=2592000; includeSubDomains" always;
}
action {…}
​
payload: Object { isAuth: false, error: true }
​
type: "auth_member"
i expect the output code like this one
but instead the web give me something else
you have to define the upstrem location to be proxed to:
# this is an example you can modify the path on as you get it
location /api {
proxy_pass http://webapp;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

Getting 'The 'Access-Control-Allow-Origin' header contains multiple values' with MEAN and nginx

I have developed an application in MEAN stack and used Nginx for HTTPS.
I have used socket.io and developed rest apis in node.
Below is my Nginx configuration;
server {
# Enable HTTP/2
listen 443 ssl;
listen [::]:443 ssl http2;
server_name api.some.com www.api.some.com;
# Use the Let’s Encrypt certificates
ssl_certificate /etc/letsencrypt/live/api.some.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.some.com/privkey.pem;
# Include the SSL configuration from cipherli.st
include snippets/ssl-params.conf;
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,from,x-auth,Access-Control-Allow-Origin';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
add_header 'Cache-Control' 'no-cache';
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,from,x-auth,Access-Control-Allow-Origin';
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,from,x-auth,Access-Control-Allow-Origin';
add_header 'Cache-Control' 'no-cache';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,from,x-auth';
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,from,x-auth';
add_header 'Cache-Control' 'no-cache';
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:5000/;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
##### changes for socket.io
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
I am getting "The 'Access-Control-Allow-Origin' header contains multiple values" error when my application is attempting to connect socket.
I have found a workout. If I comment the 'add_header' part from the GET section and add the 'Access-Control-Allow-Origin' header from my code then it is working fine. If I don't add the header in my code then the GET rest apis are not working , its asking for the 'Access-Control-Allow-Origin' header.
But I don't want to do that as nginx should handle this, my code should not bother about these headers.
What am I missing?
UPDATE :
I added 'Access-Control-Allow-Origin' in allow headers part of the GET in nginx and removed the GET specific code from node server , the get rest APIs started working BUT the socket started throwing CORS origin error.

What MongoDB user role can make POST calls?

I just have created a MongoDB instance on Ubuntu 14.04, with authentication by username:password.
The user I've created is like this:
{
"_id" : "myDatabase.myUser",
"user" : "myUser",
"db" : "myDatabase",
"roles" : [ { "role" : "readWrite", "db" : "myDatabase" } ]
}
And the URI String that I use on my REST API written in Node.js (with Express and Mongoose) is like:
mongodb://myUser:password#localhost:27017/myDatabase
The Connection is OK and the GET methods works fine, but when I use a POST method, like a signup by email/password, the response is:
Status Code:405 Not Allowed
Any idea? Thanks in advance!
FYI: I'm using Nginx as reverse proxy and Web Server for the Frontend (AngularJS app), and the config is:
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/nginx.access.log;
error_log /var/log/nginx/nginx.error.log;
location / {
expires -1;
add_header Pragma "no-cache";
add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
root /usr/share/www;
try_files $uri $uri/ /index.html =404;
}
location /api/v1 {
proxy_set_header "Access-Control-Allow-Origin";
proxy_set_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, PUT, DELETE";
proxy_set_header "Access-Control-Allow-Headers" "X-Requested-With,Accept,Content-Type, Origin";
proxy_pass http://127.0.0.1:3000/api/v1;
proxy_buffering on;
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_set_header origin "http://example.com";
}
}
I think that it isn't a mongodb restriction. Mongo can't know if the request is POST or GET. Have you verified if the request arrives at nodejs server? I think that nginx is who returns the 405 status code.
It's possible that the failure is due to try to return a static page as response to the POST request. Try adding into nginx.conf file:
# To dispatch static pages on POST request
error_page 405 = 200 $uri;
I have added the following and nginx at least works!:
proxy_redirect off;
The nginx config for default now is:
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/nginx.access.log;
error_log /var/log/nginx/nginx.error.log;
location / {
expires -1;
add_header Pragma "no-cache";
add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
root /usr/share/www;
try_files $uri $uri/ /index.html =404;
}
location /api/v1 {
proxy_set_header 'Access-Control-Allow-Origin' 'http:/example.com';
proxy_set_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
proxy_set_header 'Access-Control-Allow-Headers' 'X-Requested-With,Accept,Content-Type, Origin';
proxy_pass http://127.0.0.1:3000/api/v1;
proxy_redirect off;
proxy_buffering on;
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_set_header origin "http://example.com";
}
}
I hope this be valid for somebody.

Resources