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" 必须 附加 到您网站记录中的 domain
列 Sites 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.
我已经看过一些以前的话题了: 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" 必须 附加 到您网站记录中的 domain
列 Sites 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.