在子路径中通过nginx + uwsgi运行django app

时间:2012-07-02 10:53:33

标签: django nginx

我想在我们的开发服务器上的子目录别名中运行一个简单的测试项目。基本设置是一个nginx,其位置将子目录中的所有内容传递给wsgi应用程序。

Django显然不明白它在一个子目录别名中运行,这完全破坏了URL的生成和解析。
我在文档中找不到任何类似前缀的设置,而且我的谷歌也没有那么多帮助......所以我在这里问。

我唯一能找到的是设置FORCE_SCRIPT_NAME,它至少修复了URL的生成。 (见:http://docs.webfaction.com/software/django/config.html#mounting-a-django-application-on-a-subpath
遗憾的是,这并没有修复urlconf解析,即使提到的网站暗示了这一点。

是否可以在子目录别名中运行django应用程序,如果是,如何运行?

nginx config:

server {
        location /fancyprojectname/static {
                alias /srv/fancyprojectname/static;
        }

        location /fancyprojectname/ {
                uwsgi_pass unix://var/run/uwsgi/app/fancyprojectname/socket;
                include uwsgi_params;
        }
}

修改

所以,设置“uwsgi_param SCRIPT_NAME / fancyprojectname;”在nginx位置使FORCE_SCRIPT_NAME变得不必要 - 遗憾的是,URL匹配仍然不起作用。

from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
)

我认为发生了什么:由于管理员正则表达式以“^ admin”开头且实际网址为“fancyprojectname / admin /”,因此即使设置了SCRIPT_NAME,Django也无法正确匹配网址。

解决方案

因此,SCRIPT_NAME确实存在问题。

WSGI specification说明如下:

  

SCRIPT_NAME       请求URL的“路径”的初始部分,对应于应用程序对象,以便应用程序知道其虚拟   “地点”。如果是应用程序,这可能是一个空字符串   对应于服务器的“根”。

     

PATH_INFO   请求URL的“路径”的其余部分,指定应用程序中请求目标的虚拟“位置”。这可能是   如果请求URL以应用程序根目标为目标,则为空字符串   没有尾随斜杠。

Nginx不会自动设置SCRIPT_NAME,因此无论如何都需要设置。之后PATH_INFO是错误的,因为在默认设置中,Nginx将其设置为$ document_uri,这将是完整的URL。

“uwsgi_modifier1 30;”告诉Nginx设置UWSGI_MODIFIER_MANAGE_PATH_INFO,然后告诉UWSGI剥离PATH_INFO的SCRIPT_NAME。

这些设置的组合似乎有效,因为Django现在可以正确生成AND匹配URL。

3 个答案:

答案 0 :(得分:8)

这是假的:

  

Django显然不明白它在一个子目录别名中运行,这完全破坏了URL的生成和解析。

Django 了解这一点,并透明地处理它。服务器应该自己设置SCRIPT_NAME:你发现自己使用FORCE_SCRIPT_NAME的事实表明问题在于你的Nginx配置,而不是在Django中。

我怀疑问题是使用location,而不是更合适的指令。不幸的是,我不是Nginx / uwsgi的专家。在Apache / mod_wsgi中,您可以这样做:

WSGIScriptAlias /mysite /usr/local/django/mysite/apache/django.wsgi

告诉mod_wsgi该站点从mysite开始,而不是根目录。几乎可以肯定,nginx / uwsgi也有类似的命令。

答案 1 :(得分:5)

如果在http://www.example.com/(您的基础域)托管Django网站时此Nginx位置块有效:

location / {
    uwsgi_pass unix:/tmp/fancyprojectname.socket;
    include /etc/nginx/uwsgi_params;
}

然后这将在http://www.example.com/subpath/(基础域上的子路径)上运行:

location /subpath {
    uwsgi_pass unix:/tmp/fancyprojectname.socket;
    uwsgi_param SCRIPT_NAME /subpath; # explicitly set SCRIPT_NAME to match subpath
    uwsgi_modifier1 30; # strips SCRIPT_NAME from PATH_INFO (the url passed to Django)
    include /etc/nginx/uwsgi_params;
}

...并且无需在Django设置中设置FORCE_SCRIPT_NAME。

<强>参考文献:

答案 2 :(得分:1)

现在,在最新版本的Nginx和uWSGI中uwsgi_modifier1 30已被删除(我并不想使用一些hacky重写规则),我找到了一种更新的方法让它运作:

uWSGI config:

[uwsgi]
route-run = fixpathinfo:

Nginx配置

server {
    location /fancyprojectname/static {
        alias /srv/fancyprojectname/static;
    }

    location /fancyprojectname {
        uwsgi_pass unix://var/run/uwsgi/app/fancyprojectname/socket;
        uwsgi_param SCRIPT_NAME /fancyprojectname; # Pass the URL prefix to uWSGI so the "fixpathinfo:" route-rule can strip it out
        include uwsgi_params;
    }
}

如果它修复了它:尝试安装libpcre和libpcre-dev,然后用pip install -I --no-cache-dir uwsgi重新安装uwsgi。 uWSGI的内部路由子系统要求在编译/安装uWSGI之前安装 PCRE库。 More information on uWSGI and PCRE.