一个 Django 项目的多域托管
Posted
技术标签:
【中文标题】一个 Django 项目的多域托管【英文标题】:Multiple Domain Hosting With One Django Project 【发布时间】:2012-05-20 10:01:57 【问题描述】:我是 Django 和 python 的新手,所以请多多包涵。我想创建一个非常简单的 SaaS 应用程序来开始使用 Django 和 python。我的设计规定所有域都将在相同的代码库上运行。每个网站之间唯一不同的是数据库连接详细信息。 (IE每个域都有自己的数据库。所有数据库都包含相同的架构)
我将如何使用 Django 来解决这个问题?我已经看过 Sites 框架,但我不确定这就是我想要的。本质上,我想要么
A) 让 Django 在页面加载时从 MASTER 数据库中查找数据库连接详细信息,然后在连接到站点数据库时使用这些详细信息
B)每个站点都有一个 settings.py 并让 django 在运行时包含正确的文件(IE settings_domain.py)
C) 让索引 WSGI 包含基于访问域的适当设置文件(这似乎可行,但我确定我错过了此实现的潜在缺陷)
D) 其他一些我没想到的实现......
我是否让这变得比需要的更复杂?如何轻松将此功能实现到新的 django 项目中?
【问题讨论】:
【参考方案1】:嗯,有一个有趣的项目在:https://bitbucket.org/uysrc/django-dynamicsites。它试图让您拥有完全独特的站点,所有站点都运行在同一个项目中。但是,目前,我认为它不会对您有太大帮助,因为您需要对设置进行比它提供的更多的自定义。
我实际上只是自己做的,最初尝试使用 django-dynamicsites,但发现它有点过于敏感,不太适合我的项目。结果,我最终采取了一些不同的方法。
我的项目有一个“站点”模块,其中每个唯一站点都有一个模块。每个模块都有自己的 settings.py 和 urls.py 和模板目录。例如:
sites
- __init__.py
- site1
- __init__.py
- settings.py
- urls.py
- templates
- base.html
- site 2
- __init__.py
- settings.py
- urls.py
- templates
- base.html
每个 settings.py 大致如下:
from myproject.settings import *
SITE_ID = 1
URL_CONF = 'sites.site1.urls'
SITE_ROOT = os.path.dirname(__file__)
TEMPLATE_DIRS = (
os.path.join(SITE_ROOT, 'templates')
)
CACHE_MIDDLEWARE_KEY_PREFIX = 'site1'
因此,它的作用是导入您的项目设置文件,然后覆盖站点独有的设置。然后,您所要做的就是确保您使用的任何服务器都加载特定站点的 settings.py,而不是主项目的 settings.py。我使用的是 nginx+Gunicorn 的组合,所以大致是这样的配置:
site1.conf (nginx)
upstream site1
server 127.0.0.1:8001 fail_timeout=0;
server
listen 80;
server_name site1.domain.com;
root /path/to/project/root;
location /
try_files $uri @proxy;
location @proxy
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 10;
proxy_read_timeout 30;
proxy_pass http://site1;
proxy_redirect off;
我使用 supervisor 来管理 Gunicorn 服务器,所以这是我的配置:
site1.conf(主管)
[program:site1]
command=/path/to/virtualenv/bin/python manage.py run_gunicorn --settings=sites.site1.settings
directory=/path/to/project/root
user=www-data
autostart=true
autorestart=true
redirect_stderr=True
重要的部分是没有花哨的 Django 中间件或类似的检查特定主机并相应地以这种方式或那种方式进行。您在 uwsgi、Gunicorn 等上为每个指向正确的 settings.py 文件启动一个 Django 实例,然后您的网络服务器将每个子域的请求代理到匹配的上游连接。
【讨论】:
【参考方案2】:最好的方法是在您的网络服务器上进行重写/代理,无论是 apache 还是 nginx。在 apache 中,您可以使用类似这样的内容设置主机文件以捕获所有域。 django 将获得一个 URL,然后它可以确定它是哪个域。
<VirtualHost *:80>
ServerName domain.com
ServerAlias *
DocumentRoot /var/www/domain.com/DjangoProj/public
Alias /media/ /var/www/domain.com/DjangoProj/misc/media/
Alias /static/ /var/www/domain.com/DjangoProj/misc/static/
<Directory /var/www/domain.com/DjangoProj/public>
Order deny,allow
Allow from all
</Directory>
WSGIScriptAlias / /var/www/domain.com/DjangoProj/app/wsgi.py
<Directory /var/www/domain.com/DjangoProj/app>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %HTTP_HOST ^(.*) [NC] # Catch domain
RewriteCond %REQUEST_URI !userdomain [NC] # Don't rewrite if we already have it
RewriteRule ^(.*)$ /userdomain/%1$1 [PT,L] # Pass in PT to give the URL back to mod_python!
</IfModule>
ErrorLog /var/www/domain.com/logs/error.log
CustomLog /var/www/domain.com/logs/access.log combined
</VirtualHost>
【讨论】:
此配置使用 mod_python 和 apache2。但是这个想法可以转化为其他网络服务器配置 此配置允许您动态添加站点,而无需使用不同的文件夹结构。用户可以将网站添加到您的框架中,而无需设置新的 python 文件。例如someuser.com
=> yourdomain.com/userdomain/someuser.com
。然后你可以在你的 urlconf 等中做所有自定义的事情,然后用它做你喜欢的事情
这听起来与我的想法相似,但我无法完全理解它(对 Python 和 Django 来说都很新)我理解捕获域并将其发送到 wsgi,但我'不确定在 Python 端会发生什么以包含正确的 settings.py 文件/连接到域的正确数据库。我的想法是我们将加载一个独特的 settings.py,具体取决于所调用的域。每个 settings.py 都将具有该域唯一的数据库连接详细信息。你的想法听起来很相似,但我不确定如何最终确定它并使其发挥作用。谢谢!
如果您想为每个域建立一个单独的数据库,这不是解决方案。这允许您为一个 settings.py 和数据库托管所有域
这就是我最终想通的。那么,通过一个 Django 安装托管具有多个数据库(每个站点唯一)的多个网站的解决方案是什么?为什么我不能为每个站点创建一个唯一的 settings.py(带有相关的数据库连接详细信息),然后将每个域的 index.wsgi 指向正确的 settings.py。那不行吗?我打算这个周末尝试建立一个测试服务器,并可以测试这个理论,但想先看看是否有更好的方法。以上是关于一个 Django 项目的多域托管的主要内容,如果未能解决你的问题,请参考以下文章