如果你想用nginx反代grafana,那么很有可能参考了官网文档Run Grafana behind a reverse proxy,看了一眼,非常简单,不就是改几个参数,加个location嘛!
“小case”,你对自己说到,十分钟解决。
那么在参考结束之后,你很有可能遇到这个错误。
随即你进行了搜索,问题还挺多,中文的英文的,然后自己不停地尝试,grafana和nginx的配置都快改花了,发现还是不行。于是两个小时过去了。这究竟是为什么呢?
作为一名有灵性的工程师,当你看到如图所示的画面时,应该会想到哪些事情呢?
- 这个橙色的文字,绝对不是Nginx的,看起来更像是grafana的,那么也就是说请求转发给了grafana
- 既然如此,那么看下控制台吧!
哟呵,怎么都是404呢,难道是由于一些路径的原因,导致proxy_pass的时候出错了?
于是你又一顿查,proxy_set_header
等全都加上了,路径结尾带不带/
也都排列组合了一圈,发现还是不行!?
作为一名有灵性的工程师,此时自然就要想,难道是grafana有bug?把router_logging
打开……此时你突然看到,这个文件名好奇怪啊,这么长。难道文件真的不存在吗?
内心无比刺痛,什么?!另一边的你,甚至拿出来了curl
~$ curl -L https://dmesg.app/grafana/public/build/app.4141596c10e564d57dfb.js <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx</center> </body> </html> ~$ curl -L https://dmesg.app/grafana/public/build/1.txt hello!
???
那zip文件呢?
$ curl -L https://dmesg.app/grafana/public/build/1.zip a zip(not really)
那js呢?
~$ curl -L https://dmesg.app/grafana/public/build/1.js <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx</center> </body> </html> ~$
????
突然,你看到了一处这样的配置:
location ~ .*\.(js|css|woff)?$ { expires 30d; }
这段的意思是,正则匹配,结尾是js、css和woff,expire设置成30天。于是你在脑海里迅速过了一遍nginx的location匹配优先级,好像似乎是正则比路径匹配的优先级要高。
于是你以迅雷不及掩耳盗铃之速把原先的配置
location /grafana/ { proxy_pass http://localhost:3000; }
中的第一个/
改成了~
,也就是
location ~/grafana/ { proxy_pass http://localhost:3000; }
然后restart或reload nginx,刷新页面,好了!此刻看看时间,天啊,三个小时过去了,快一点了……
也就是说,一个~
价值三小时,如果按照时薪来算,这一笔,很值钱啊!
点评
其实以上就是我昨晚的完整经过,一开始的时候,大部分时间完全就是在“瞎?找死?”,当然网上提到的方案都是没用的,毕竟没有找到问题的根本原因。所以如果早点通过橙色的字体发现问题出在js 404,那么问题就应该会更快解决了。
哎呀年轻人?♀️还是要学会通过现象看本质的,不要瞎猫碰上死耗子呀!
解释一下:如果你的nginx开启了css、js的cache,想在sub directory下反代grafana,那么按照官网的文档去做失败的概率是非常高的。
原因非常简单:js和css都404了。因为正则匹配的优先级高于path匹配,所以全被cache的location截胡了。解决方案也很简单,把grafana那段的/
换成~
,当然 ~/grafana/
和~ grafana/
都是无所谓的啦,正则嘛!还不放心的话,再放到location开头。
当然了,需要注意的是,不仅仅是子目录时会发生这种情况,子域名时,只要设置了这种cache规则,那么就一定会出错的。
配置cache的人还不少,已经给官方发了PR,希望他们能及早修复吧。
完整配置和解释
grafana
# 只让grafana监听127,反代没必要监听0.0.0.0 http_addr =127.0.0.1 # 域名,都懂 domain = dmesg.app # Grafana内部的一些url(比如警告的url)都是根据这个来的,其实可以看出来这里其实是格式化字符串,domain就是上面的那个 root_url= https://%(domain)s/grafana/ # 子目录就要true serve_from_sub_path = true
nginx
# ~表示正则匹配,区分大小写 location ~grafana/ { proxy_pass http://localhost:3000; } location ~ .*\.(js|css|woff)?$ { expires 30d; }
参考资料
Nginx location priority https://stackoverflow.com/questions/5238377/nginx-location-priority