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

Posted

技术标签:

【中文标题】在子路径中通过 nginx+uwsgi 运行 django app【英文标题】:Run django app via nginx+uwsgi in a subpath 【发布时间】:2012-07-02 18:45:15 【问题描述】:

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

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

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

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

nginx 配置:

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”开头并且实际 URL 是“fancyprojectname/admin/”,因此即使设置了 SCRIPT_NAME,Django 也无法正确匹配 URL。

解决方案

所以,这确实是 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 现在可以正确生成和匹配 URL。

【问题讨论】:

请查看***.com/a/40496307/1588163 在那里您将找到完成此操作的更新方法 See also: How to Mount Django App with uwsgi 【参考方案1】:

现在uwsgi_modifier1 30 在最新版本的 Nginx 和 uWSGI 中被删除(我不想使用一些 hacky 的重写规则),我必须找到一个更新的方法来获取它工作:

uWSGI 配置:

[uwsgi]
# Requires PCRE support compiled into 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.

【讨论】:

这是最终的解决方案 这个解决方案至少对我来说是 django 3+ 的最佳解决方案。只需修改我所有的绝对路径并将它们切换为 url/reverse 过滤器。【参考方案2】:

这是错误的:

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 也有类似的命令。

【讨论】:

好的,我用“uwsgi_param SCRIPT_NAME /fancyprojectname;”试过这个在 nginx 中,这似乎“有效”,因为我现在可以在设置中注释掉 FORCE_SCRIPT_NAME 并且正确生成 URL - 这仍然不能修复 URL 匹配。我将在问题中附加当前的 url 配置。 看起来它现在正在工作 - SCRIPT_NAME 不够,设置“uwsgi_modifier1 30;”虽然这样做。我不知道这个设置有什么作用,但是当我发现我会再次更新问题并接受这个作为有效答案。谢谢指点! 我必须补充一点,“uwsgi_modifier1 30”这只是答案的一半。对我有用的是在我的 uwsgi.ini 文件中添加“env = DJANGO_SETTINGS_MODULE=my_app.settings”【参考方案3】:

如果在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。

参考资料:

Strayer 的原始 cmets 和问题发布的解决方案。 https://uwsgi-docs.readthedocs.org/en/latest/Nginx.html https://www.python.org/dev/peps/pep-0333/(完整的 WSGI 规范)

【讨论】:

谢谢,现在我有Hatta wiki在nginx下的子路径中运行。 不要忘记将“env = DJANGO_SETTINGS_MODULE=your_app.settings”添加到您的 uwsgi.ini 文件中。

以上是关于在子路径中通过 nginx+uwsgi 运行 django app的主要内容,如果未能解决你的问题,请参考以下文章

django Nginx部署

Django + uwsgi + nginx。导入错误:没有名为py的模块

python 使用Nginx和uWSGI来运行Python应用

Nginx + uwsgi 时,替换路径。

nginx + uwsgi 部署 Django+Vue项目

Nginx 从特定路径为另一个域的 Django(uWSGI 套接字)提供服务