uwsgi_pass不转发SCRIPT_NAME标头

时间:2019-07-12 15:13:52

标签: django docker nginx uwsgi

我正在尝试从主域的某些子文件夹中提供我的Web应用程序(基于Django / wsgi)。 我将docker用于我的应用程序和静态文件,因此我在服务器上使用了主要的nginx作为反向代理,在“ nginx”容器中使用了另一个nginx,用于将我的应用程序和uWSGI的内容路由到第二个容器中,该容器用于提供实际的Django数据 scheme

并且我希望我的应用可以以myserver.com/mytool的形式在外部使用,与此同时,我不想在应用中的任何位置对mytool进行硬编码。通常SCRIPT_NAME标头用于这种类型的东西,因此这是主机上的Nginx配置:

server {
  listen 80; # Just for sake of simplicity, of course in production it's 443 with SSL
  location /mytool/ {
    proxy_pass http://127.0.0.1:8000/;
    include proxy_params;
    proxy_set_header SCRIPT_NAME /mytool;  # <--- Here I define my header which backend should use
  }
}

然后在我的docker-compose中,我为nginx公开了8000:80,这是内部nginx配置:

server {
  listen 80;
  location / {
    include uwsgi_params;
    uwsgi_pass web:3031;
  }
}

通过这种配置,我希望我的Django应用接收到SCRIPT_NAME标头,但显然没有。

同时,如果我定义了自定义标头,例如proxy_set_header X-something something;,则它会正确转发,并且可以从Django中看到它。

我应该如何传递SCRIPT_NAME以避免在代码中使用路径硬编码?

1 个答案:

答案 0 :(得分:0)

这里有两个问题。

首先,nginx将包含下划线的标头视为无效,因此SCRIPT_NAME标头不被容器中的nginx接受,因为从nginx角度来看,它是无效的。幸运的是,nginx指令underscores_in_headers可以为您提供帮助。

只需将underscores_in_headers on;添加到Docker内部的nginx server部分(而不添加到主机)。

完成此操作后,还有另一个问题-nginx在其名称前面转发在标题HTTP之前的标头。因此,现在从Django端您将看到HTTP_SCRIPT_NAME而不是SCRIPT_NAME。但是,再次幸运的是,可以再次在Docker内部的nginx中使用uwsgi_param SCRIPT_NAME $http_script_name;行来轻松修复它。

因此,Docker内部的最终nginx配置应如下所示:

server {
  underscores_in_headers on;  # <---- (1)
  listen 80;
  location / {
    include uwsgi_params;
    uwsgi_pass web:3031;
    uwsgi_param SCRIPT_NAME $http_script_name; # <--- (2)        
  }
}