Nginx – Proxying grafana with nginx works but fails to load grafana js files

grafananginxreverse-proxy

I am trying to integrate Grafana dashboards in a web application. The use of grafana URLs in the web app was failing for CORS errors. After searching on grafana community website found that Grafana as not support and suggested to use a reverse proxy to get rid of the CORS. So added nginx. I could get rid of the CORS errors after adding the required config in nginx.conf file but the Grafana is still failing to load. Following is the config and the problem I am facing –

  • Using nginx-1.15.5 on windows 10

Following are the configs on my machine –

grafana custom.ini

http_port = 3000
domain = localhost
root_url = %(protocol)s://%(domain)s/grafana/

nginx.conf

worker_processes  1;
error_log  logs/error.log debug;
events {
    worker_connections  1024;
}
http {
    server {
       listen 80;
       root C:\\installables\\nginx-1.15.5\\www;
       index index.html index.htm;
       server_name localhost;      

       location /grafana/ {       

          proxy_pass http://localhost:3000/;
          rewrite  ^/grafana/(.*)  /$1 break;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          if ($request_method = 'OPTIONS') {
             add_header 'Access-Control-Allow-Origin' "*";
             #add_header 'Access-Control-Allow-Credentials' 'true' always;
             add_header 'Access-Control-Allow-Methods' 'GET, POST, 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;
            return 204;
           }             

           add_header 'Access-Control-Allow-Origin' "*";
           add_header 'Access-Control-Allow-Methods' 'GET, POST, 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;
           add_header 'Access-Control-Expose-Headers' 'Content-Type,Content-Length,Content-Range';

           proxy_set_header X-Forwarded-Host $host;
           proxy_set_header X-Forwarded-Server $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;          

       }
    }    
}

Application running on

http://localhost:9121/

has following JSP file calling code to invoke the Grafana and show it in an iframe.

<script language="javaScript">
    $.ajax({
        type: "GET", 
        url: "http://localhost/grafana/",
        contentType: "application/json",
        xhrFields: {
            withCredentials: false
        },
        headers: {
            // Set any custom headers here.
        },        
        success: function(data){
            $("#monitoringframe").attr('srcdoc',data)
        },
        error : function(err) {
            console.log('Error!', err)
        }            
    });
</script>

<iframe name="monitoringframe" id="monitoringframe" src="about:blank" sandbox="allow-forms allow-popups allow-same-origin allow-scripts" width=100% height=600 border="0" frameborder="0" />

Grafana URL works with no CORS issues but fails while loading the grafana javascript files. I am not sure why the js files are being looked over

http://localhost:9121

which is calling application URL. They should have been invoked with URL like

http://localhost/grafana/public/build/

Following are the logs from Chrome dev console

20:24:33.392 XHR finished loading: OPTIONS "http://localhost/grafana/".
20:24:33.409 XHR finished loading: GET "http://localhost/grafana/".
20:24:33.411 XHR finished loading: OPTIONS "http://localhost/grafana/login".
20:24:33.449 XHR finished loading: GET "http://localhost/grafana/login".
20:24:33.451 VM25370 about:srcdoc:281 GET http://localhost:9121/grafana/public/build/vendor.4ad1072db19f1dad74f5.js net::ERR_ABORTED 404 (Not Found)
20:24:33.452 VM25370 about:srcdoc:269 GET http://localhost:9121/grafana/public/build/grafana.dark.css?v5.3.2+0d821d0 net::ERR_ABORTED 404 (Not Found)
20:24:33.456 VM25370 about:srcdoc:281 GET http://localhost:9121/grafana/public/build/app.4ad1072db19f1dad74f5.js net::ERR_ABORTED 404 (Not Found)

Need your help to understand what is wrong here and how to make it work.

Best Answer

This worked for me after a couple of changes. The first one being the important one which helped fix this issue.

  1. Put the web application as well behind the proxy. Earlier I was login into the web app using the port number and then after loading the monitoring page, it was trying to load the grafana into an iframe using reverse-proxy. I did a lot of debugging and tried so many ngnix config changes to make it work and then thought of adding a rewrite rule to send the request to grafana. And for that i had to put the application behind the reverse-proxy as well. But that single change made the difference and there was no need to add any rewrite rule. Following is the modified nginx.conf file

    worker_processes 1; #error_log logs/error.log debug; events { worker_connections 1024; } http { server { listen 80;

        root C:\\installables\\nginx-1.15.5\\www;
        index index.html index.htm;
        server_name localhost;
    
        location /grafana/ {       
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
    
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
            add_header 'Access-Control-Expose-Headers' 'Content-Type,Content-Length,Content-Range';
            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;           
    
            if ($request_method = 'OPTIONS') {
              return 204;
            }            
            proxy_pass http://localhost:3000/;          
        }
        location / {  
           proxy_pass http://localhost:9121/;          
        }      
     }    
    

    }

  2. had to correct the buggy function code to load the response content in the iframe. Here that specific modified change.

     success: function(data){
         var iframeDoc = $("#monitoringframe").get(0).contentDocument;
         iframeDoc.open();
         iframeDoc.write(data);
         iframeDoc.close();
     }