2

I have Grafana set up in a Docker container (grafana/grafana image from Docker repo) with port 3000 forwarded to my localhost. My docker-compose.yml below:

version: '2.1'
services:
  grafana:
    image: grafana/grafana
    ports:
      - 3000:3000

Originally I also have link to Graphite and some volumes and environment configuration (GF_SECURITY_ADMIN_PASSWORD only) but I suppose it does not matter.

I can get a response from Grafana via simple curl call:

$ curl http://localhost:3000
<a href="/login">Found</a>.

But when I am trying to get it via AJAX call, it gives me a weird result:

$.ajax({url: 'http://localhost:3000', beforeSend: function(xhr, settings) {alert('before setting header'); xhr.setRequestHeader('Access-Control-Allow-Origin', '*'); alert('after setting header');}});
[many JSON fields]
responseText:""
[many JSON fields]
statusText: "error"
[many JSON fields]

Alerts says that header is set to accept requests from any origin.

The same happens (curl works but ajax not) when I am calling Docker container address directly.

What happens in the background? Why the second request does not work? How can I get response from Grafana via AJAX call?

pt12lol
  • 2,332
  • 1
  • 22
  • 48

1 Answers1

3

The issue is the by default CORS is not enabled on grafana. A curl request doesn't check for CORS but a browser does. It is what protect one site to call API of other sites.

So your solution would be to put a reverse nginx proxy in front of Grafana. Below is the docker-compose.yml for the same

version: '2.1'
services:
  grafana:
    image: grafana/grafana
  nginx:
    image: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
      - "3000:80"

And below nginx config will add CORS to it, but it is very open would allow everyone access

events {
    worker_connections  1024;
}

http {
#
# Acts as a nginx HTTPS proxy server
# enabling CORS only to domains matched by regex
# /https?://.*\.mckinsey\.com(:[0-9]+)?)/
#
# Based on:
# * http://blog.themillhousegroup.com/2013/05/nginx-as-cors-enabled-https-proxy.html
# * http://enable-cors.org/server_nginx.html
#
server {
  listen 80;

  location / {
    #if ($http_origin ~* (https?://.*\.tarunlalwani\.com(:[0-9]+)?$)) {
    #   set $cors "1";
    #}
    set $cors "1";

    # OPTIONS indicates a CORS pre-flight request
    if ($request_method = 'OPTIONS') {
       set $cors "${cors}o";
    }

    # Append CORS headers to any request from
    # allowed CORS domain, except OPTIONS
    if ($cors = "1") {
       add_header Access-Control-Allow-Origin $http_origin always;
       add_header Access-Control-Allow-Credentials  true always;
       proxy_pass      http://grafana:3000;
    }

    # OPTIONS (pre-flight) request from allowed
    # CORS domain. return response directly
    if ($cors = "1o") {
       add_header 'Access-Control-Allow-Origin' '$http_origin' always;
       add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
       add_header 'Access-Control-Allow-Credentials' 'true' always;
       add_header 'Access-Control-Allow-Headers' 'Origin,Content-Type,Accept' always;
       add_header Content-Length 0;
       add_header Content-Type text/plain;
       return 204;
    }

    # Requests from non-allowed CORS domains
       proxy_pass      http://grafana:3000;
  }
}

}

Also for test you should not use

 xhr.setRequestHeader('Access-Control-Allow-Origin', '*');

Remove that and test and it should work

CORS Access working

Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • hold on, this does make sense, but I can't see connection between nginx and grafana containers. why ports are 3000:80? looks like localhost on 3000 can see not grafana but nginx service. I didn't try it yet, but that were questions coming to my mind after deeper look into your answer. After trying applying your suggestions, more detailed feedback will be provided. – pt12lol Aug 24 '17 at 06:28
  • Nginx listens on `80` and `grafana` on `3000`. So we proxy pass in nginx using `http://grafana:3000;` and expose the nginx port `80` as `3000` – Tarun Lalwani Aug 24 '17 at 06:38
  • ok, still doesn't work. I added your nginx service to my target docker-compose and added `links: grafana` clause. it seems necessary to me because I don't know how nginx can make Grafana work. Can you provide the exact command you are using in order to run `docker-compose.yml` file you advised me? – pt12lol Aug 24 '17 at 08:09
  • I tested and posted. You don't need to add links. Which version of docker did you test it on? I have latest `17.06-ce` – Tarun Lalwani Aug 24 '17 at 08:11
  • `Docker version 1.12.6, build 78d1802` – pt12lol Aug 24 '17 at 08:11
  • Upgrade it, `docker-compose` will automatically create the network and using `links` is now `deprecated` – Tarun Lalwani Aug 24 '17 at 08:13
  • tried just before a minute under Firefox and then in a new tab in Chrome and it worked. issue resolved. – pt12lol Aug 24 '17 at 12:50
  • Not sure, this is a 4 yr old answer, you will have to check. Grafana might be giving cors options directly now – Tarun Lalwani Feb 25 '21 at 06:36