nginx 通过 uWSGI 在子目录中为 Django 提供服务

nginx serving Django in a subdirectory through uWSGI

我已经看过一些以前的话题了: How do I set subdirectory in nginx with Django how to deploy django under a suburl behind nginx Serving flask app on subdirectory nginx + uwsgi

基本的教训是,您只需配置您的站点(可用)即可实现此目的。我现在尝试了

的各种排列
server {
    listen 80;
    server_name www.example.com;

    location = /favicon.ico { 
        access_log off; 
        log_not_found off; 
    }

    location /static/ {
        root /path/to/project;
    }

    location /project/ {
        root            /path/to/project;
        include         /etc/nginx/uwsgi_params;
        uwsgi_param     SCRIPT_NAME /project;
        uwsgi_modifier1 30;
        uwsgi_param PATH_INFO "";
        uwsgi_pass      unix:/tmp/project.sock;
    }
}

当我将 location 定义为“/”(并删除 SCRIPT_NAME、modifier1、PATH_INFO 和 root 时,一切都运行完美。但是尝试使用子目录总是会导致 Page未找到 (404):

Request URL:    http://www.example.com/project/project

(edit) 它正在向请求中添加一个目录。我有什么想不通的?

(试过 forced_script_name - 不应该使用这个并给其他类型的头痛 - 和 uwsgi 配置设置)

编辑:

location /project/ {
    root            /path/to/project;
    include         /etc/nginx/uwsgi_params;
    uwsgi_param     SCRIPT_NAME /project;
    uwsgi_pass      unix:/tmp/project.sock;
}

不起作用...当我为 / 配置时,套接字就在那里并且可以工作 - 我只是看不到我缺少的东西。

更新:

location ~ /project(?<path_info>/.*|$) {
    include         /etc/nginx/uwsgi_params;
    uwsgi_pass      unix:/tmp/project.sock;
    uwsgi_param     PATH_INFO $path_info;
    uwsgi_param     SCRIPT_NAME /project;
}

这会加载站点,但所有链接都指向 http://example.com/link/to/something instead of http://example.com/project/link/to/something

首先,移除uwsgi_modifier1 30;。 Django 将自己处理 SCRIPT_NAME 并且不需要由 uWSGI 重写 PATH_INFO 。如果 SCRIPT_NAME 没有被 uWSGI 从 headers 中移除,这可能是有害的。

其次,从 nginx 配置中删除 uwsgi_param PATH_INFO "";PATH_INFO 已经在 uwsgi_params 文件中定义,它应该是 $document_uri(因为它在 uwsgi_params 中),而不是 </code> 如果你传递 <code>SCRIPT_NAME 到 django。

在那次调整之后,django 应该将 SCRIPT_NAME 视为 URL 前缀,并将调整 url 调度程序和 url 与之相反。

如果应用程序非常简单,可以在 urls.py 中的一行中添加一个简单的“/前缀”,那么我更喜欢这个简单的解决方案。

否则 "/prefix" 必须 附加 到您网站记录中的 domainSites table 在 Django 管理中。域应该是 "example.com/project" 第二个解决方案,因为 Django 必须知道域和前缀,尤其是正确的重定向。当然,网络服务器还必须从请求的 URL 中删除前缀,就像您现在在 nginx 设置中所做的那样。

我通常将此类部署的验证分为两个问题:

  • 是否向 Django 报告 Web 服务器 (nginx) 预期的更短或更长的 URLs?
  • 是否知道 Django 的完整基础 URL 并且它是否在所有网页中始终如一地使用它?

我同时启用了 nginx 日志和 Django 日志记录,以查看它们中的哪一个最终被错误配置了。 (您没有写足够的重要信息。)

一个应该测试的重要案例是:验证需要认证的网页是否正确地来回重定向到登录页面,即使您在注销后尝试这些 URLs。

可以在 similar question 中找到更多详细信息。

最终放弃尝试这样做"neatly"。

最终解决方案只是创建一个设置变量,我将其作为前缀添加到 static_url 和项目 urls.py 文件中。没有 SCRIPT_NAME 或 nginx 方面的任何复杂内容。

nginx uwsgi_modifier1 在 uWSGI 中被弃用。

您的目标是能够从任何地方托管 wsgi 应用程序,而无需调整该应用程序以说明它的服务来源。

当前在 uWSGI 中执行此操作的方法是为每个 URI 应用程序组合映射挂载点,如下所示:

[uwsgi]
socket = 127.0.0.1:3031
; mount apps
mount = /app1=app1.py
mount = /app2=app2.py
; rewrite SCRIPT_NAME and PATH_INFO accordingly
manage-script-name = true

Hosting multiple apps in the same process (aka managing SCRIPT_NAME and PATH_INFO)

mount可以代替module

特别是对于 Django,

; Before
module = django_app.wsgi:application
; After
mount = /django_app=django_app.wsgi:application
manage-script-name = true

最新 Nginx/uWSGI 版本的最干净方法

由于 uwsgi_modifier1 30 在最新版本中被 删除,我觉得 mount-point 的东西太老套了,我不得不使用 newer method 在子目录中为 Django 提供服务:

uWSGI 配置:

[uwsgi]
socket =        /tmp/project.sock

# Requires PCRE support compiled into uWSGI
route-run =     fixpathinfo:

Nginx 配置:

location /project {
    include         /etc/nginx/uwsgi_params;
    uwsgi_pass      unix:/tmp/project.sock;
    uwsgi_param     SCRIPT_NAME /project; # Pass the URL prefix to uWSGI so the "fixpathinfo:" route-rule can strip it out
}

注意:fixpathinfo: 需要将 PCRE 支持编译成 uWSGI。

因此,如果事情不起作用,请尝试安装 libpcre 和 libpcre-dev,然后使用 pip install -I --no-cache-dir uwsgi 重新编译 uwsgi。 uWSGI 的内部路由子系统需要在 之前 安装 PCRE 库,uWSGI 是 compiled/installed。 More information on uWSGI and PCRE.